]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.8-20230219
authorWietse Venema <wietse@porcupine.org>
Sun, 19 Feb 2023 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Mon, 20 Feb 2023 01:07:15 +0000 (20:07 -0500)
47 files changed:
postfix/HISTORY
postfix/README_FILES/SASL_README
postfix/WISHLIST
postfix/html/SASL_README.html
postfix/html/lmtp.8.html
postfix/html/postconf.5.html
postfix/html/posttls-finger.1.html
postfix/html/smtp.8.html
postfix/html/smtpd.8.html
postfix/man/man1/posttls-finger.1
postfix/man/man5/postconf.5
postfix/man/man8/smtp.8
postfix/man/man8/smtpd.8
postfix/mantools/postlink
postfix/proto/SASL_README.html
postfix/proto/postconf.proto
postfix/proto/stop
postfix/proto/stop.double-history
postfix/proto/stop.double-proto-html
postfix/proto/stop.spell-cc
postfix/proto/stop.spell-history
postfix/proto/stop.spell-proto-html
postfix/src/dns/dns.h
postfix/src/dns/dns_lookup.c
postfix/src/dns/dns_rr.c
postfix/src/dns/dns_rr_eq_sa.c
postfix/src/dns/dns_sa_to_rr.c
postfix/src/dns/dns_str_resflags.c
postfix/src/dns/dns_strrecord.c
postfix/src/dns/dns_strtype.c
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/posttls-finger/posttls-finger.c
postfix/src/smtp/lmtp_params.c
postfix/src/smtp/smtp.c
postfix/src/smtp/smtp.h
postfix/src/smtp/smtp_addr.c
postfix/src/smtp/smtp_addr.h
postfix/src/smtp/smtp_connect.c
postfix/src/smtp/smtp_params.c
postfix/src/smtp/smtp_reuse.c
postfix/src/smtp/smtp_session.c
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd_check.c
postfix/src/util/attr.h
postfix/src/util/sys_defs.h
postfix/src/util/unix_send_fd.c

index d1545c53a4203c08284a8e1c2c0444fc45c901ee..5041f17cff5e34eb1092def0012e3fb5c414f7bf 100644 (file)
@@ -26808,3 +26808,73 @@ Apologies for any names omitted.
 
        Portability: MacOS support for the postfix-env.sh test
        script.
+
+20230129
+
+       Documentation: in the postconf(5) manpage, the text for
+       append_dot_mydomain described old default behavior. File:
+       proto/postconf.proto.
+
+       Documentation: in the smtpd(8) manpage, the text for the
+       info_log_address_format parameter was in the wrong place.
+       File: smtpd/smtpd.c.
+
+20230202
+
+       Documentation: fixed a broken HTML tag in SASL_README.html.
+
+20230209
+
+       Cleanup: noise suppression for resolver-related macros.
+       Viktor Dukhovni. Files: dns/dns_str_resflags.c, util/sys_defs.h.
+
+20230212
+
+       Cleanup: valgrind complained about uninitialized padding.
+       File: util/unix_send_fd.c
+
+20230213
+
+       Feature: SRV lookup support in the Postfix SMTP/LMTP client.
+       See https://www.postfix.org/postconf.5.html#use_srv_lookup.
+       Based on code by Tomas Korbar (Red Hat). Files: proto/stop,
+       proto/stop.spell-proto-html, dns/dns.h, dns/dns_lookup.c,
+       dns/dns_rr.c, dns/dns_sa_to_rr.c, dns/dns_strrecord.c,
+       dns/dns_strtype.c, global/mail_params.h, smtp/lmtp_params.c,
+       smtp/smtp_addr.c, smtp/smtp_addr.h, smtp/smtp.c,
+       smtp/smtp_connect.c, smtp/smtp.h, smtp/smtp_params.c,
+       smtp/smtp_session.c, smtpd/smtpd_check.c, util/attr.h,
+       util/unix_send_fd.c, mantools/postlink, proto/postconf.proto.
+
+20230214
+
+       SRV lookup: propagate preference and port information when
+       converting a numerical hostname to IP address. File:
+       smtp/smtp_addr.c.
+
+       SRV lookup: add SRV support to the posttls-finger command.
+       File: posttls-finger/posttls-finger.c.
+
+       SRV lookup: updated documentation examples. File:
+       proto/postconf.proto.
+
+20230219
+
+       Code health: replaced a proliferation of 'bare' zero arguments
+       with named constants: DNS_RR_NOPREF, DNS_RR_NOWEIGHT,
+       DNS_RR_NOPORT, and added convenience wrappers for
+       dns_rr_create(), to simplify code that needs to specify
+       only a subset of all arguments. Files: src/dns/dns.h,
+       src/dns/dns_rr_eq_sa.c, src/dns/dns_sa_to_rr.c,
+       src/smtpd/smtpd_check.c.
+
+       Code health: updated internal documentation. Files:
+       dns/dns_rr.c, smtp/smtp_connect.c.
+
+       Compatibility: downgraded some modernisms to avoid breaking
+       builds on older test systems. File: dns/dns_rr.c.
+
+       Code health: simplified the SRV record priority grouping
+       and record ordering code. Eliminated some special-case
+       handling of zero-weight records (that was already started
+       in the initial implementation). File: dns/dns_rr.c.
index 580a0131d3e450b3c41b8469b0c1f7cec0d01d87..4ea62d9b36eb8932f078340f78d53c0aa233085f 100644 (file)
@@ -174,24 +174,23 @@ You can read more about the following topics:
 
   * Cyrus SASL version 2.1.22 and newer additionally search in /etc/sasl2/.
 
-  * li>
-    With Postfix 2.5 and later you can explicitly configure the search path via
+  * With Postfix 2.5 and later you can explicitly configure the search path via
     the cyrus_sasl_config_path configuration parameter. Specify zero or more
     colon-separated directories. If set empty (the default value) the search
     path is the one compiled into the Cyrus SASL library.
 
-Some Postfix distributions employ a non-empty default value for
-cyrus_sasl_config_path to look for the Cyrus SASL configuration file in /etc/
-postfix/sasl/, /var/lib/sasl2/ etc. See the output of postconf
-cyrus_sasl_config_path and/or the distribution-specific documentation to
-determine the expected location.
-
-Some Debian-based Postfix distributions patch Postfix to hardcode a non-default
-search path, making it impossible to set an alternate search path via the
-"cyrus_sasl_config_path" parameter. This is likely to be the case when the
-distribution documents a Postfix-specific path (e.g. /etc/postfix/sasl/) that
-is different from the default value of "cyrus_sasl_config_path" (which then is
-likely to be empty).
+  * Some Postfix distributions employ a non-empty default value for
+    cyrus_sasl_config_path to look for the Cyrus SASL configuration file in /
+    etc/postfix/sasl/, /var/lib/sasl2/ etc. See the output of postconf
+    cyrus_sasl_config_path and/or the distribution-specific documentation to
+    determine the expected location.
+
+  * Some Debian-based Postfix distributions patch Postfix to hardcode a non-
+    default search path, making it impossible to set an alternate search path
+    via the "cyrus_sasl_config_path" parameter. This is likely to be the case
+    when the distribution documents a Postfix-specific path (e.g. /etc/postfix/
+    sasl/) that is different from the default value of "cyrus_sasl_config_path"
+    (which then is likely to be empty).
 
     N\bNo\bot\bte\be
 
index bee364895917d761473244259f7d004c2818c2a2..71b1685caab1d2281f86b7364e94cb8affaecb68 100644 (file)
@@ -9,7 +9,12 @@ Wish list:
        Scan Postfix code with github.com/googleprojectzero/weggli
        (depends on "rust").
 
-       In smtpd.c, move the comment block with info_log_address_format.
+       Follow https://github.com/vdukhovni/postfix/commits/rpk
+
+       Multi-recipient support in sender/recipient_bcc_maps and
+       always_bcc.
+
+       Should "postconf -f" pretty-print text inside {}?
 
        Is there any code that calls attr_scan*() and that works
        when the number of attributes received < the expected number?
index f3139166815c7bb39353d911bc513b46e0699bed..1ddd24bb2adb7608265dd2385762869622cd8aa2 100644 (file)
@@ -267,7 +267,7 @@ in <code>/usr/lib/sasl2/</code>. </p> </li>
 <li> <p> Cyrus SASL version 2.1.22 and newer additionally search
 in <code>/etc/sasl2/</code>. </p> </li>
 
-li> <p> With Postfix 2.5 and later you can explicitly configure the
+<li> <p> With Postfix 2.5 and later you can explicitly configure the
 search path via the <code><a href="postconf.5.html#cyrus_sasl_config_path">cyrus_sasl_config_path</a></code> configuration
 parameter. Specify zero or more colon-separated directories. If
 set empty (the default value) the search path is the one compiled
index bcdb904b94a74588fdcbda940689f544899d2332..696d3bf4c4639f6bb21c411b7b07d5da66253d26 100644 (file)
@@ -152,6 +152,7 @@ SMTP(8)                                                                SMTP(8)
        <a href="https://tools.ietf.org/html/rfc2046">RFC 2046</a> (MIME: Media Types)
        <a href="https://tools.ietf.org/html/rfc2554">RFC 2554</a> (AUTH command)
        <a href="https://tools.ietf.org/html/rfc2821">RFC 2821</a> (SMTP protocol)
+       <a href="https://tools.ietf.org/html/rfc2782">RFC 2782</a> (SRV resource records)
        <a href="https://tools.ietf.org/html/rfc2920">RFC 2920</a> (SMTP Pipelining)
        <a href="https://tools.ietf.org/html/rfc3207">RFC 3207</a> (STARTTLS command)
        <a href="https://tools.ietf.org/html/rfc3461">RFC 3461</a> (SMTP DSN Extension)
@@ -395,6 +396,21 @@ SMTP(8)                                                                SMTP(8)
        <b><a href="postconf.5.html#header_from_format">header_from_format</a> (standard)</b>
               The format of the Postfix-generated <b>From:</b> header.
 
+       Available in Postfix version 3.8 and later:
+
+       <b><a href="postconf.5.html#use_srv_lookup">use_srv_lookup</a> (empty)</b>
+              Enables discovery for the specified  service(s)  using  DNS  SRV
+              records.
+
+       <b><a href="postconf.5.html#ignore_srv_lookup_error">ignore_srv_lookup_error</a> (no)</b>
+              When  SRV  record  lookup  fails,  fall back to MX or IP address
+              lookup as if SRV record lookups were not enabled.
+
+       <b><a href="postconf.5.html#allow_srv_lookup_fallback">allow_srv_lookup_fallback</a> (no)</b>
+              When SRV record lookup fails or no SRV record exists, fall  back
+              to  MX  or  IP  address lookup as if SRV record lookups were not
+              enabled.
+
 <b>MIME PROCESSING CONTROLS</b>
        Available in Postfix version 2.0 and later:
 
index 95c8dca568826b910f52637795c59510b72591bb..722bdc4ec99049d7240d432d0e4576fc44e1d8ca 100644 (file)
@@ -762,6 +762,17 @@ Example:
 </pre>
 
 
+</DD>
+
+<DT><b><a name="allow_srv_lookup_fallback">allow_srv_lookup_fallback</a>
+(default: no)</b></DT><DD>
+
+<p> When SRV record lookup fails or no SRV record exists, fall back
+to MX or IP address lookup as if SRV record lookup was not enabled. <p>
+
+<p> This feature is available in Postfix 3.8 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="allow_untrusted_routing">allow_untrusted_routing</a>
@@ -946,7 +957,7 @@ instead.
 </p>
 
 <p>
-Note 1: this feature is enabled by default. If disabled, users will not be
+Note 1: When disabled (Postfix 3.0 and later), users will not be
 able to send mail to "user@partialdomainname" but will have to
 specify full domain names instead.
 </p>
@@ -4017,6 +4028,17 @@ mis-delivery of mail.
 </p>
 
 
+</DD>
+
+<DT><b><a name="ignore_srv_lookup_error">ignore_srv_lookup_error</a>
+(default: no)</b></DT><DD>
+
+<p> When SRV record lookup fails, fall back to MX or IP address
+lookup as if SRV record lookup was not enabled. </>
+
+<p> This feature is available in Postfix 3.8 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="import_environment">import_environment</a>
@@ -21247,6 +21269,103 @@ only if it would otherwise be accepted. </p>
 <p> This feature is available in Postfix 2.6 and later. </p>
 
 
+</DD>
+
+<DT><b><a name="use_srv_lookup">use_srv_lookup</a>
+(default: empty)</b></DT><DD>
+
+<p> Enables discovery for the specified service(s) using DNS SRV
+records. For example, with "<a href="postconf.5.html#use_srv_lookup">use_srv_lookup</a> = submission" and
+"<a href="postconf.5.html#relayhost">relayhost</a> = example.com:submission", the Postfix SMTP client will
+look up DNS SRV records for _submission._tcp.example.com, and will
+relay email through the hosts and ports that are specified with
+those records. See <a href="https://tools.ietf.org/html/rfc2782">RFC 2782</a> for details of the host selection
+process. </p>
+
+<p> Specify zero or more service names separated by comma and/or
+whitespace. Any name in the services(5) database may be specified,
+though in practice only submission, submissions, and smtp make
+sense.  </p>
+
+<p> When SRV record lookup is enabled with <a href="postconf.5.html#use_srv_lookup">use_srv_lookup</a>, you can
+enclose a domain name in "[]" to force IP address lookup instead
+of SRV record lookup. </p>
+
+<p> Example 1: MUA-to-MTA submission using SRV record lookup for
+the "submission" service for domain "example.com". This uses the
+default SMTP delivery agent with STARTTLS, and looks up SRV records
+for "_submission._tcp.example.com". </p>
+
+<pre>
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+    <a href="postconf.5.html#use_srv_lookup">use_srv_lookup</a> = submission
+    <a href="postconf.5.html#relayhost">relayhost</a> = example.com:submission
+    <a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = may
+    ...see <a href="SASL_README.html">SASL_README</a> for sasl configuration...
+</pre>
+
+<p> Example 2: MUA-to-MTA submission using SRV record lookup for
+the "submissions" service for domain "example.org". This uses a
+dedicated SMTP delivery agent (smtp-wraptls) with tls_wrappermode
+turned on, and looks up SRV records for "_submissions._tcp.example.org".
+</p>
+
+<p> Note: specify the older name "smtps" instead of "submissions"
+when a provider has DNS SRV records like "_smtps._tcp.example.org"
+instead of "_submissions._tcp.example.org". </p>
+
+<pre>
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+    <a href="postconf.5.html#use_srv_lookup">use_srv_lookup</a> = submissions
+    <a href="postconf.5.html#default_transport">default_transport</a> = smtp-wraptls:example.org:submissions
+    ...see <a href="SASL_README.html">SASL_README</a> for sasl configuration...
+</pre>
+
+<pre>
+/etc/postfix/<a href="master.5.html">master.cf</a>:
+    smtp-wraptls   unix   ...   ...   ...   ...   ...   smtp
+        -o { <a href="postconf.5.html#smtp_tls_wrappermode">smtp_tls_wrappermode</a> = yes }
+        -o { <a href="postconf.5.html#smtp_tls_security_level">smtp_tls_security_level</a> = encrypt }
+</pre>
+
+<p> Example 3: Sender-dependent selection for a combination of
+MUA-to-MTA submission services. This combines examples 1 and 2 with
+examples of how to disable SRV and look up IP address records for
+"smtp-relay.example.net" and "smtp-relay.other.example".  Again,
+specify the older name "smtps" instead of "submissions" when a
+provider has DNS SRV records like "_smtps._tcp.example.org" instead
+of "_submissions._tcp.example.org". </p>
+
+<pre>
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+    <a href="postconf.5.html#use_srv_lookup">use_srv_lookup</a> = submission, submissions
+    <a href="postconf.5.html#sender_dependent_default_transport_maps">sender_dependent_default_transport_maps</a> = <a href="DATABASE_README.html#types">inline</a>:{
+        # Destinations that support SRV record lookup.
+        { user1@example.com = <a href="smtp.8.html">smtp</a>:example.com:submission }
+        { user2@example.org = smtp-wraptls:example.org:submissions }
+        # Use [destination] to force IP address lookups.
+        { user3@example.net = <a href="smtp.8.html">smtp</a>:[smtp-relay.example.net]:submission }
+        { user4@other.example =
+              smtp-wraptls:[smtp-relay.other.example]:submissions } }
+    ...see <a href="SASL_README.html">SASL_README</a> for sasl configuration...
+</pre>
+
+<p> Example 4: MTA-to-MTA traffic, using SRV record lookup for the
+SMTP service. This is useful for Postfix tests, and may be useful
+in environments where ports are dynamically assigned to servers.
+</p>
+
+<pre>
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
+    <a href="postconf.5.html#use_srv_lookup">use_srv_lookup</a> = smtp
+    # Fall back to MX record lookup when SRV records are unavailable.
+    #<a href="postconf.5.html#allow_srv_lookup_fallback">allow_srv_lookup_fallback</a> = yes
+    #<a href="postconf.5.html#ignore_srv_lookup_error">ignore_srv_lookup_error</a> = yes
+</pre>
+
+<p> This feature is available in Postfix 3.8 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="verp_delimiter_filter">verp_delimiter_filter</a>
index 401ad0726e0831a96a32a366ef2857d4b9dd2c35..877a2fa6722a89d8f49fca1c4fcd2feea53270a6 100644 (file)
@@ -271,6 +271,8 @@ POSTTLS-FINGER(1)                                            POSTTLS-FINGER(1)
               the  <b>-m</b>  option.  By default reconnection is disabled, specify a
               positive delay to enable this behavior.
 
+       <b>-R</b>     Use SRV lookup instead of MX.
+
        <b>-s</b> <i>servername</i>
               The server name to send with  the  TLS  Server  Name  Indication
               (SNI)  extension.   When  the server has DANE TLSA records, this
index bcdb904b94a74588fdcbda940689f544899d2332..696d3bf4c4639f6bb21c411b7b07d5da66253d26 100644 (file)
@@ -152,6 +152,7 @@ SMTP(8)                                                                SMTP(8)
        <a href="https://tools.ietf.org/html/rfc2046">RFC 2046</a> (MIME: Media Types)
        <a href="https://tools.ietf.org/html/rfc2554">RFC 2554</a> (AUTH command)
        <a href="https://tools.ietf.org/html/rfc2821">RFC 2821</a> (SMTP protocol)
+       <a href="https://tools.ietf.org/html/rfc2782">RFC 2782</a> (SRV resource records)
        <a href="https://tools.ietf.org/html/rfc2920">RFC 2920</a> (SMTP Pipelining)
        <a href="https://tools.ietf.org/html/rfc3207">RFC 3207</a> (STARTTLS command)
        <a href="https://tools.ietf.org/html/rfc3461">RFC 3461</a> (SMTP DSN Extension)
@@ -395,6 +396,21 @@ SMTP(8)                                                                SMTP(8)
        <b><a href="postconf.5.html#header_from_format">header_from_format</a> (standard)</b>
               The format of the Postfix-generated <b>From:</b> header.
 
+       Available in Postfix version 3.8 and later:
+
+       <b><a href="postconf.5.html#use_srv_lookup">use_srv_lookup</a> (empty)</b>
+              Enables discovery for the specified  service(s)  using  DNS  SRV
+              records.
+
+       <b><a href="postconf.5.html#ignore_srv_lookup_error">ignore_srv_lookup_error</a> (no)</b>
+              When  SRV  record  lookup  fails,  fall back to MX or IP address
+              lookup as if SRV record lookups were not enabled.
+
+       <b><a href="postconf.5.html#allow_srv_lookup_fallback">allow_srv_lookup_fallback</a> (no)</b>
+              When SRV record lookup fails or no SRV record exists, fall  back
+              to  MX  or  IP  address lookup as if SRV record lookups were not
+              enabled.
+
 <b>MIME PROCESSING CONTROLS</b>
        Available in Postfix version 2.0 and later:
 
index 965bf11ffe0b18bb3b773b08c2bd3234fa8f1b8f..f60ee85d0828dbada196c30e1ad0dc47dafa30f5 100644 (file)
@@ -159,32 +159,38 @@ SMTPD(8)                                                              SMTPD(8)
        <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.
 
+       Available in Postfix 3.5 and later:
+
+       <b><a href="postconf.5.html#info_log_address_format">info_log_address_format</a> (external)</b>
+              The email address form that will be used  in  non-debug  logging
+              (info, warning, etc.).
+
        Available in Postfix version 3.6 and later:
 
        <b><a href="postconf.5.html#smtpd_relay_before_recipient_restrictions">smtpd_relay_before_recipient_restrictions</a> (see 'postconf -d' output)</b>
-              Evaluate    <a href="postconf.5.html#smtpd_relay_restrictions">smtpd_relay_restrictions</a>    before     <a href="postconf.5.html#smtpd_recipient_restrictions">smtpd_recipi</a>-
+              Evaluate     <a href="postconf.5.html#smtpd_relay_restrictions">smtpd_relay_restrictions</a>    before    <a href="postconf.5.html#smtpd_recipient_restrictions">smtpd_recipi</a>-
               <a href="postconf.5.html#smtpd_recipient_restrictions">ent_restrictions</a>.
 
-       <b><a href="postconf.5.html#known_tcp_ports">known_tcp_ports</a>   (lmtp=24,   smtp=25,  smtps=submissions=465,  submis-</b>
+       <b><a href="postconf.5.html#known_tcp_ports">known_tcp_ports</a>  (lmtp=24,  smtp=25,   smtps=submissions=465,   submis-</b>
        <b>sion=587)</b>
-              Optional  setting  that  avoids lookups in the <b>services</b>(5) data-
+              Optional setting that avoids lookups in  the  <b>services</b>(5)  data-
               base.
 
        Available in Postfix version 3.7 and later:
 
        <b><a href="postconf.5.html#smtpd_per_request_deadline">smtpd_per_request_deadline</a> (normal: no, overload: yes)</b>
               Change  the  behavior  of  the  <a href="postconf.5.html#smtpd_timeout">smtpd_timeout</a>  and  <a href="postconf.5.html#smtpd_starttls_timeout">smtpd_start</a>-
-              <a href="postconf.5.html#smtpd_starttls_timeout">tls_timeout</a>  time limits, from a time limit per plaintext or TLS
-              read or write call, to a combined time  limit  for  receiving  a
-              complete  SMTP request and for sending a complete SMTP response.
+              <a href="postconf.5.html#smtpd_starttls_timeout">tls_timeout</a> time limits, from a time limit per plaintext or  TLS
+              read  or  write  call,  to a combined time limit for receiving a
+              complete SMTP request and for sending a complete SMTP  response.
 
        <b><a href="postconf.5.html#smtpd_min_data_rate">smtpd_min_data_rate</a> (500)</b>
-              The minimum plaintext data transfer  rate  in  bytes/second  for
-              DATA   and  BDAT  requests,  when  deadlines  are  enabled  with
+              The  minimum  plaintext  data  transfer rate in bytes/second for
+              DATA  and  BDAT  requests,  when  deadlines  are  enabled   with
               <a href="postconf.5.html#smtpd_per_request_deadline">smtpd_per_request_deadline</a>.
 
 <b>ADDRESS REWRITING CONTROLS</b>
-       See the <a href="ADDRESS_REWRITING_README.html">ADDRESS_REWRITING_README</a> document for a detailed discussion  of
+       See  the <a href="ADDRESS_REWRITING_README.html">ADDRESS_REWRITING_README</a> document for a detailed discussion of
        Postfix address rewriting.
 
        <b><a href="postconf.5.html#receive_override_options">receive_override_options</a> (empty)</b>
@@ -194,34 +200,34 @@ SMTPD(8)                                                              SMTPD(8)
        Available in Postfix version 2.2 and later:
 
        <b><a href="postconf.5.html#local_header_rewrite_clients">local_header_rewrite_clients</a> (<a href="postconf.5.html#permit_inet_interfaces">permit_inet_interfaces</a>)</b>
-              Rewrite or add message  headers  in  mail  from  these  clients,
-              updating  incomplete addresses with the domain name in $<a href="postconf.5.html#myorigin">myorigin</a>
+              Rewrite  or  add  message  headers  in  mail from these clients,
+              updating incomplete addresses with the domain name in  $<a href="postconf.5.html#myorigin">myorigin</a>
               or $<a href="postconf.5.html#mydomain">mydomain</a>, and adding missing headers.
 
 <b>BEFORE-SMTPD PROXY AGENT</b>
        Available in Postfix version 2.10 and later:
 
        <b><a href="postconf.5.html#smtpd_upstream_proxy_protocol">smtpd_upstream_proxy_protocol</a> (empty)</b>
-              The name of the proxy protocol used by an optional  before-smtpd
+              The  name of the proxy protocol used by an optional before-smtpd
               proxy agent.
 
        <b><a href="postconf.5.html#smtpd_upstream_proxy_timeout">smtpd_upstream_proxy_timeout</a> (5s)</b>
-              The  time  limit  for  the  proxy  protocol  specified  with the
+              The time  limit  for  the  proxy  protocol  specified  with  the
               <a href="postconf.5.html#smtpd_upstream_proxy_protocol">smtpd_upstream_proxy_protocol</a> parameter.
 
 <b>AFTER QUEUE EXTERNAL CONTENT INSPECTION CONTROLS</b>
-       As of version 1.0, Postfix can be configured to send  new  mail  to  an
-       external  content  filter AFTER the mail is queued. This content filter
-       is expected to inject mail back into a (Postfix or other) MTA for  fur-
+       As  of  version  1.0,  Postfix can be configured to send new mail to an
+       external content filter AFTER the mail is queued. This  content  filter
+       is  expected to inject mail back into a (Postfix or other) MTA for fur-
        ther delivery. See the <a href="FILTER_README.html">FILTER_README</a> document for details.
 
        <b><a href="postconf.5.html#content_filter">content_filter</a> (empty)</b>
-              After  the  message  is  queued,  send the entire message to the
+              After the message is queued, send  the  entire  message  to  the
               specified <i>transport:destination</i>.
 
 <b>BEFORE QUEUE EXTERNAL CONTENT INSPECTION CONTROLS</b>
-       As of version 2.1, the Postfix SMTP server can be  configured  to  send
-       incoming  mail  to a real-time SMTP-based content filter BEFORE mail is
+       As  of  version  2.1, the Postfix SMTP server can be configured to send
+       incoming mail to a real-time SMTP-based content filter BEFORE  mail  is
        queued.  This content filter is expected to inject mail back into Post-
        fix.  See the <a href="SMTPD_PROXY_README.html">SMTPD_PROXY_README</a> document for details on how to config-
        ure and operate this feature.
@@ -230,40 +236,40 @@ SMTPD(8)                                                              SMTPD(8)
               The hostname and TCP port of the mail filtering proxy server.
 
        <b><a href="postconf.5.html#smtpd_proxy_ehlo">smtpd_proxy_ehlo</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
-              How the Postfix SMTP server announces itself to the  proxy  fil-
+              How  the  Postfix SMTP server announces itself to the proxy fil-
               ter.
 
        <b><a href="postconf.5.html#smtpd_proxy_options">smtpd_proxy_options</a> (empty)</b>
-              List  of options that control how the Postfix SMTP server commu-
+              List of options that control how the Postfix SMTP server  commu-
               nicates with a before-queue content filter.
 
        <b><a href="postconf.5.html#smtpd_proxy_timeout">smtpd_proxy_timeout</a> (100s)</b>
-              The time limit for connecting to a proxy filter and for  sending
+              The  time limit for connecting to a proxy filter and for sending
               or receiving information.
 
 <b>BEFORE QUEUE MILTER CONTROLS</b>
        As of version 2.3, Postfix supports the Sendmail version 8 Milter (mail
-       filter) protocol. These content filters run outside Postfix.  They  can
-       inspect  the  SMTP  command  stream  and  the  message content, and can
-       request modifications before mail is queued. For details see  the  <a href="MILTER_README.html">MIL</a>-
+       filter)  protocol.  These content filters run outside Postfix. They can
+       inspect the SMTP command  stream  and  the  message  content,  and  can
+       request  modifications  before mail is queued. For details see the <a href="MILTER_README.html">MIL</a>-
        <a href="MILTER_README.html">TER_README</a> document.
 
        <b><a href="postconf.5.html#smtpd_milters">smtpd_milters</a> (empty)</b>
-              A  list  of  Milter (mail filter) applications for new mail that
+              A list of Milter (mail filter) applications for  new  mail  that
               arrives via the Postfix <a href="smtpd.8.html"><b>smtpd</b>(8)</a> server.
 
        <b><a href="postconf.5.html#milter_protocol">milter_protocol</a> (6)</b>
-              The mail filter protocol version and  optional  protocol  exten-
-              sions  for  communication  with  a  Milter application; prior to
+              The  mail  filter  protocol version and optional protocol exten-
+              sions for communication with  a  Milter  application;  prior  to
               Postfix 2.6 the default protocol is 2.
 
        <b><a href="postconf.5.html#milter_default_action">milter_default_action</a> (tempfail)</b>
-              The default action when  a  Milter  (mail  filter)  response  is
-              unavailable  (for  example,  bad Postfix configuration or Milter
+              The  default  action  when  a  Milter  (mail filter) response is
+              unavailable (for example, bad Postfix  configuration  or  Milter
               failure).
 
        <b><a href="postconf.5.html#milter_macro_daemon_name">milter_macro_daemon_name</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
-              The {daemon_name} macro value for Milter (mail filter)  applica-
+              The  {daemon_name} macro value for Milter (mail filter) applica-
               tions.
 
        <b><a href="postconf.5.html#milter_macro_v">milter_macro_v</a> ($<a href="postconf.5.html#mail_name">mail_name</a> $<a href="postconf.5.html#mail_version">mail_version</a>)</b>
@@ -274,60 +280,60 @@ SMTPD(8)                                                              SMTPD(8)
               tion, and for negotiating protocol options.
 
        <b><a href="postconf.5.html#milter_command_timeout">milter_command_timeout</a> (30s)</b>
-              The time limit for sending an SMTP command  to  a  Milter  (mail
+              The  time  limit  for  sending an SMTP command to a Milter (mail
               filter) application, and for receiving the response.
 
        <b><a href="postconf.5.html#milter_content_timeout">milter_content_timeout</a> (300s)</b>
-              The  time  limit  for  sending message content to a Milter (mail
+              The time limit for sending message content  to  a  Milter  (mail
               filter) application, and for receiving the response.
 
        <b><a href="postconf.5.html#milter_connect_macros">milter_connect_macros</a> (see 'postconf -d' output)</b>
-              The macros that are sent to Milter  (mail  filter)  applications
+              The  macros  that  are sent to Milter (mail filter) applications
               after completion of an SMTP connection.
 
        <b><a href="postconf.5.html#milter_helo_macros">milter_helo_macros</a> (see 'postconf -d' output)</b>
-              The  macros  that  are sent to Milter (mail filter) applications
+              The macros that are sent to Milter  (mail  filter)  applications
               after the SMTP HELO or EHLO command.
 
        <b><a href="postconf.5.html#milter_mail_macros">milter_mail_macros</a> (see 'postconf -d' output)</b>
-              The macros that are sent to Milter  (mail  filter)  applications
+              The  macros  that  are sent to Milter (mail filter) applications
               after the SMTP MAIL FROM command.
 
        <b><a href="postconf.5.html#milter_rcpt_macros">milter_rcpt_macros</a> (see 'postconf -d' output)</b>
-              The  macros  that  are sent to Milter (mail filter) applications
+              The macros that are sent to Milter  (mail  filter)  applications
               after the SMTP RCPT TO command.
 
        <b><a href="postconf.5.html#milter_data_macros">milter_data_macros</a> (see 'postconf -d' output)</b>
-              The macros that are sent to version 4  or  higher  Milter  (mail
+              The  macros  that  are  sent to version 4 or higher Milter (mail
               filter) applications after the SMTP DATA command.
 
        <b><a href="postconf.5.html#milter_unknown_command_macros">milter_unknown_command_macros</a> (see 'postconf -d' output)</b>
-              The  macros  that  are  sent to version 3 or higher Milter (mail
+              The macros that are sent to version 3  or  higher  Milter  (mail
               filter) applications after an unknown SMTP command.
 
        <b><a href="postconf.5.html#milter_end_of_header_macros">milter_end_of_header_macros</a> (see 'postconf -d' output)</b>
-              The macros that are sent to Milter  (mail  filter)  applications
+              The  macros  that  are sent to Milter (mail filter) applications
               after the end of the message header.
 
        <b><a href="postconf.5.html#milter_end_of_data_macros">milter_end_of_data_macros</a> (see 'postconf -d' output)</b>
-              The  macros  that  are sent to Milter (mail filter) applications
+              The macros that are sent to Milter  (mail  filter)  applications
               after the message end-of-data.
 
        Available in Postfix version 3.1 and later:
 
        <b><a href="postconf.5.html#milter_macro_defaults">milter_macro_defaults</a> (empty)</b>
-              Optional list of <i>name=value</i> pairs that  specify  default  values
-              for  arbitrary  macros  that Postfix may send to Milter applica-
+              Optional  list  of  <i>name=value</i> pairs that specify default values
+              for arbitrary macros that Postfix may send  to  Milter  applica-
               tions.
 
        Available in Postfix version 3.2 and later:
 
        <b><a href="postconf.5.html#smtpd_milter_maps">smtpd_milter_maps</a> (empty)</b>
-              Lookup tables with Milter settings per  remote  SMTP  client  IP
+              Lookup  tables  with  Milter  settings per remote SMTP client IP
               address.
 
 <b>GENERAL CONTENT INSPECTION CONTROLS</b>
-       The  following parameters are applicable for both built-in and external
+       The following parameters are applicable for both built-in and  external
        content filters.
 
        Available in Postfix version 2.1 and later:
@@ -337,51 +343,51 @@ SMTPD(8)                                                              SMTPD(8)
               ing, or address mapping.
 
 <b>EXTERNAL CONTENT INSPECTION CONTROLS</b>
-       The  following  parameters  are  applicable  for  both before-queue and
+       The following parameters  are  applicable  for  both  before-queue  and
        after-queue content filtering.
 
        Available in Postfix version 2.1 and later:
 
        <b><a href="postconf.5.html#smtpd_authorized_xforward_hosts">smtpd_authorized_xforward_hosts</a> (empty)</b>
-              What remote SMTP clients are allowed to use  the  XFORWARD  fea-
+              What  remote  SMTP  clients are allowed to use the XFORWARD fea-
               ture.
 
 <b>SASL AUTHENTICATION CONTROLS</b>
        Postfix SASL support (<a href="https://tools.ietf.org/html/rfc4954">RFC 4954</a>) can be used to authenticate remote SMTP
-       clients to the Postfix SMTP server, and  to  authenticate  the  Postfix
-       SMTP  client to a remote SMTP server.  See the <a href="SASL_README.html">SASL_README</a> document for
+       clients  to  the  Postfix  SMTP server, and to authenticate the Postfix
+       SMTP client to a remote SMTP server.  See the <a href="SASL_README.html">SASL_README</a> document  for
        details.
 
        <b><a href="postconf.5.html#broken_sasl_auth_clients">broken_sasl_auth_clients</a> (no)</b>
-              Enable interoperability with remote SMTP clients that  implement
+              Enable  interoperability with remote SMTP clients that implement
               an obsolete version of the AUTH command (<a href="https://tools.ietf.org/html/rfc4954">RFC 4954</a>).
 
        <b><a href="postconf.5.html#smtpd_sasl_auth_enable">smtpd_sasl_auth_enable</a> (no)</b>
               Enable SASL authentication in the Postfix SMTP server.
 
        <b><a href="postconf.5.html#smtpd_sasl_local_domain">smtpd_sasl_local_domain</a> (empty)</b>
-              The  name of the Postfix SMTP server's local SASL authentication
+              The name of the Postfix SMTP server's local SASL  authentication
               realm.
 
        <b><a href="postconf.5.html#smtpd_sasl_security_options">smtpd_sasl_security_options</a> (noanonymous)</b>
               Postfix SMTP server SASL security options; as of Postfix 2.3 the
-              list  of available features depends on the SASL server implemen-
+              list of available features depends on the SASL server  implemen-
               tation that is selected with <b><a href="postconf.5.html#smtpd_sasl_type">smtpd_sasl_type</a></b>.
 
        <b><a href="postconf.5.html#smtpd_sender_login_maps">smtpd_sender_login_maps</a> (empty)</b>
-              Optional lookup table with the SASL login  names  that  own  the
+              Optional  lookup  table  with  the SASL login names that own the
               sender (MAIL FROM) addresses.
 
        Available in Postfix version 2.1 and later:
 
        <b><a href="postconf.5.html#smtpd_sasl_exceptions_networks">smtpd_sasl_exceptions_networks</a> (empty)</b>
-              What  remote SMTP clients the Postfix SMTP server will not offer
+              What remote SMTP clients the Postfix SMTP server will not  offer
               AUTH support to.
 
        Available in Postfix version 2.1 and 2.2:
 
        <b><a href="postconf.5.html#smtpd_sasl_application_name">smtpd_sasl_application_name</a> (smtpd)</b>
-              The application name that the Postfix SMTP server uses for  SASL
+              The  application name that the Postfix SMTP server uses for SASL
               server initialization.
 
        Available in Postfix version 2.3 and later:
@@ -392,11 +398,11 @@ SMTPD(8)                                                              SMTPD(8)
 
        <b><a href="postconf.5.html#smtpd_sasl_path">smtpd_sasl_path</a> (smtpd)</b>
               Implementation-specific information that the Postfix SMTP server
-              passes  through  to  the  SASL  plug-in  implementation  that is
+              passes through  to  the  SASL  plug-in  implementation  that  is
               selected with <b><a href="postconf.5.html#smtpd_sasl_type">smtpd_sasl_type</a></b>.
 
        <b><a href="postconf.5.html#smtpd_sasl_type">smtpd_sasl_type</a> (cyrus)</b>
-              The SASL plug-in type that the Postfix SMTP  server  should  use
+              The  SASL  plug-in  type that the Postfix SMTP server should use
               for authentication.
 
        Available in Postfix version 2.5 and later:
@@ -408,7 +414,7 @@ SMTPD(8)                                                              SMTPD(8)
        Available in Postfix version 2.11 and later:
 
        <b><a href="postconf.5.html#smtpd_sasl_service">smtpd_sasl_service</a> (smtp)</b>
-              The service name that is passed to  the  SASL  plug-in  that  is
+              The  service  name  that  is  passed to the SASL plug-in that is
               selected with <b><a href="postconf.5.html#smtpd_sasl_type">smtpd_sasl_type</a></b> and <b><a href="postconf.5.html#smtpd_sasl_path">smtpd_sasl_path</a></b>.
 
        Available in Postfix version 3.4 and later:
@@ -420,20 +426,20 @@ SMTPD(8)                                                              SMTPD(8)
        Available in Postfix 3.6 and later:
 
        <b><a href="postconf.5.html#smtpd_sasl_mechanism_filter">smtpd_sasl_mechanism_filter</a> (!external, <a href="DATABASE_README.html#types">static</a>:rest)</b>
-              If non-empty, a filter for the SASL  mechanism  names  that  the
+              If  non-empty,  a  filter  for the SASL mechanism names that the
               Postfix SMTP server will announce in the EHLO response.
 
 <b>STARTTLS SUPPORT CONTROLS</b>
-       Detailed  information  about STARTTLS configuration may be found in the
+       Detailed information about STARTTLS configuration may be found  in  the
        <a href="TLS_README.html">TLS_README</a> document.
 
        <b><a href="postconf.5.html#smtpd_tls_security_level">smtpd_tls_security_level</a> (empty)</b>
-              The SMTP TLS security level for the Postfix SMTP server; when  a
+              The  SMTP TLS security level for the Postfix SMTP server; when a
               non-empty value is specified, this overrides the obsolete param-
               eters <a href="postconf.5.html#smtpd_use_tls">smtpd_use_tls</a> and <a href="postconf.5.html#smtpd_enforce_tls">smtpd_enforce_tls</a>.
 
        <b><a href="postconf.5.html#smtpd_sasl_tls_security_options">smtpd_sasl_tls_security_options</a> ($<a href="postconf.5.html#smtpd_sasl_security_options">smtpd_sasl_security_options</a>)</b>
-              The SASL authentication security options that the  Postfix  SMTP
+              The  SASL  authentication security options that the Postfix SMTP
               server uses for TLS encrypted SMTP sessions.
 
        <b><a href="postconf.5.html#smtpd_starttls_timeout">smtpd_starttls_timeout</a> (see 'postconf -d' output)</b>
@@ -441,25 +447,25 @@ SMTPD(8)                                                              SMTPD(8)
               during TLS startup and shutdown handshake procedures.
 
        <b><a href="postconf.5.html#smtpd_tls_CAfile">smtpd_tls_CAfile</a> (empty)</b>
-              A file containing (PEM  format)  CA  certificates  of  root  CAs
+              A  file  containing  (PEM  format)  CA  certificates of root CAs
               trusted to sign either remote SMTP client certificates or inter-
               mediate CA certificates.
 
        <b><a href="postconf.5.html#smtpd_tls_CApath">smtpd_tls_CApath</a> (empty)</b>
-              A directory containing (PEM format) CA certificates of root  CAs
+              A  directory containing (PEM format) CA certificates of root CAs
               trusted to sign either remote SMTP client certificates or inter-
               mediate CA certificates.
 
        <b><a href="postconf.5.html#smtpd_tls_always_issue_session_ids">smtpd_tls_always_issue_session_ids</a> (yes)</b>
-              Force the Postfix SMTP server to issue a TLS  session  id,  even
-              when   TLS   session   caching  is  turned  off  (<a href="postconf.5.html#smtpd_tls_session_cache_database">smtpd_tls_ses</a>-
+              Force  the  Postfix  SMTP server to issue a TLS session id, even
+              when  TLS  session  caching  is   turned   off   (<a href="postconf.5.html#smtpd_tls_session_cache_database">smtpd_tls_ses</a>-
               <a href="postconf.5.html#smtpd_tls_session_cache_database">sion_cache_database</a> is empty).
 
        <b><a href="postconf.5.html#smtpd_tls_ask_ccert">smtpd_tls_ask_ccert</a> (no)</b>
               Ask a remote SMTP client for a client certificate.
 
        <b><a href="postconf.5.html#smtpd_tls_auth_only">smtpd_tls_auth_only</a> (no)</b>
-              When TLS encryption is optional in the Postfix SMTP  server,  do
+              When  TLS  encryption is optional in the Postfix SMTP server, do
               not announce or accept SASL authentication over unencrypted con-
               nections.
 
@@ -470,18 +476,18 @@ SMTPD(8)                                                              SMTPD(8)
               File with the Postfix SMTP server RSA certificate in PEM format.
 
        <b><a href="postconf.5.html#smtpd_tls_exclude_ciphers">smtpd_tls_exclude_ciphers</a> (empty)</b>
-              List  of ciphers or cipher types to exclude from the SMTP server
+              List of ciphers or cipher types to exclude from the SMTP  server
               cipher list at all TLS security levels.
 
        <b><a href="postconf.5.html#smtpd_tls_dcert_file">smtpd_tls_dcert_file</a> (empty)</b>
               File with the Postfix SMTP server DSA certificate in PEM format.
 
        <b><a href="postconf.5.html#smtpd_tls_dh1024_param_file">smtpd_tls_dh1024_param_file</a> (empty)</b>
-              File  with DH parameters that the Postfix SMTP server should use
+              File with DH parameters that the Postfix SMTP server should  use
               with non-export EDH ciphers.
 
        <b><a href="postconf.5.html#smtpd_tls_dh512_param_file">smtpd_tls_dh512_param_file</a> (empty)</b>
-              File with DH parameters that the Postfix SMTP server should  use
+              File  with DH parameters that the Postfix SMTP server should use
               with export-grade EDH ciphers.
 
        <b><a href="postconf.5.html#smtpd_tls_dkey_file">smtpd_tls_dkey_file</a> ($<a href="postconf.5.html#smtpd_tls_dcert_file">smtpd_tls_dcert_file</a>)</b>
@@ -494,12 +500,12 @@ SMTPD(8)                                                              SMTPD(8)
               Enable additional Postfix SMTP server logging of TLS activity.
 
        <b><a href="postconf.5.html#smtpd_tls_mandatory_ciphers">smtpd_tls_mandatory_ciphers</a> (medium)</b>
-              The  minimum  TLS cipher grade that the Postfix SMTP server will
+              The minimum TLS cipher grade that the Postfix SMTP  server  will
               use with mandatory TLS encryption.
 
        <b><a href="postconf.5.html#smtpd_tls_mandatory_exclude_ciphers">smtpd_tls_mandatory_exclude_ciphers</a> (empty)</b>
-              Additional list of ciphers or cipher types to exclude  from  the
-              Postfix  SMTP  server cipher list at mandatory TLS security lev-
+              Additional  list  of ciphers or cipher types to exclude from the
+              Postfix SMTP server cipher list at mandatory TLS  security  lev-
               els.
 
        <b><a href="postconf.5.html#smtpd_tls_mandatory_protocols">smtpd_tls_mandatory_protocols</a> (see 'postconf -d' output)</b>
@@ -508,21 +514,21 @@ SMTPD(8)                                                              SMTPD(8)
 
        <b><a href="postconf.5.html#smtpd_tls_received_header">smtpd_tls_received_header</a> (no)</b>
               Request that the Postfix SMTP server produces Received:  message
-              headers that include information about the protocol  and  cipher
-              used,  as  well  as the remote SMTP client CommonName and client
+              headers  that  include information about the protocol and cipher
+              used, as well as the remote SMTP client  CommonName  and  client
               certificate issuer CommonName.
 
        <b><a href="postconf.5.html#smtpd_tls_req_ccert">smtpd_tls_req_ccert</a> (no)</b>
-              With mandatory TLS encryption, require  a  trusted  remote  SMTP
+              With  mandatory  TLS  encryption,  require a trusted remote SMTP
               client certificate in order to allow TLS connections to proceed.
 
        <b><a href="postconf.5.html#smtpd_tls_wrappermode">smtpd_tls_wrappermode</a> (no)</b>
-              Run the Postfix SMTP server in TLS "wrapper"  mode,  instead  of
+              Run  the  Postfix  SMTP server in TLS "wrapper" mode, instead of
               using the STARTTLS command.
 
        <b><a href="postconf.5.html#tls_daemon_random_bytes">tls_daemon_random_bytes</a> (32)</b>
-              The  number  of  pseudo-random bytes that an <a href="smtp.8.html"><b>smtp</b>(8)</a> or <a href="smtpd.8.html"><b>smtpd</b>(8)</a>
-              process requests from the <a href="tlsmgr.8.html"><b>tlsmgr</b>(8)</a> server in order to seed  its
+              The number of pseudo-random bytes that an  <a href="smtp.8.html"><b>smtp</b>(8)</a>  or  <a href="smtpd.8.html"><b>smtpd</b>(8)</a>
+              process  requests from the <a href="tlsmgr.8.html"><b>tlsmgr</b>(8)</a> server in order to seed its
               internal pseudo random number generator (PRNG).
 
        <b><a href="postconf.5.html#tls_high_cipherlist">tls_high_cipherlist</a> (see 'postconf -d' output)</b>
@@ -538,41 +544,41 @@ SMTPD(8)                                                              SMTPD(8)
               The OpenSSL cipherlist for "export" or higher grade ciphers.
 
        <b><a href="postconf.5.html#tls_null_cipherlist">tls_null_cipherlist</a> (eNULL:!aNULL)</b>
-              The  OpenSSL  cipherlist  for  "NULL" grade ciphers that provide
+              The OpenSSL cipherlist for "NULL"  grade  ciphers  that  provide
               authentication without encryption.
 
        Available in Postfix version 2.5 and later:
 
        <b><a href="postconf.5.html#smtpd_tls_fingerprint_digest">smtpd_tls_fingerprint_digest</a> (see 'postconf -d' output)</b>
-              The  message  digest  algorithm   to   construct   remote   SMTP
-              client-certificate   fingerprints  or  public  key  fingerprints
-              (Postfix  2.9  and  later)  for  <b><a href="postconf.5.html#check_ccert_access">check_ccert_access</a></b>   and   <b>per-</b>
+              The   message   digest   algorithm   to  construct  remote  SMTP
+              client-certificate  fingerprints  or  public  key   fingerprints
+              (Postfix   2.9   and  later)  for  <b><a href="postconf.5.html#check_ccert_access">check_ccert_access</a></b>  and  <b>per-</b>
               <b>mit_tls_clientcerts</b>.
 
        Available in Postfix version 2.6 and later:
 
        <b><a href="postconf.5.html#smtpd_tls_protocols">smtpd_tls_protocols</a> (see postconf -d output)</b>
-              TLS  protocols  accepted  by the Postfix SMTP server with oppor-
+              TLS protocols accepted by the Postfix SMTP  server  with  oppor-
               tunistic TLS encryption.
 
        <b><a href="postconf.5.html#smtpd_tls_ciphers">smtpd_tls_ciphers</a> (medium)</b>
-              The minimum TLS cipher grade that the Postfix SMTP  server  will
+              The  minimum  TLS cipher grade that the Postfix SMTP server will
               use with opportunistic TLS encryption.
 
        <b><a href="postconf.5.html#smtpd_tls_eccert_file">smtpd_tls_eccert_file</a> (empty)</b>
-              File  with the Postfix SMTP server ECDSA certificate in PEM for-
+              File with the Postfix SMTP server ECDSA certificate in PEM  for-
               mat.
 
        <b><a href="postconf.5.html#smtpd_tls_eckey_file">smtpd_tls_eckey_file</a> ($<a href="postconf.5.html#smtpd_tls_eccert_file">smtpd_tls_eccert_file</a>)</b>
-              File with the Postfix SMTP server ECDSA private key in PEM  for-
+              File  with the Postfix SMTP server ECDSA private key in PEM for-
               mat.
 
        <b><a href="postconf.5.html#smtpd_tls_eecdh_grade">smtpd_tls_eecdh_grade</a> (see 'postconf -d' output)</b>
-              The  Postfix  SMTP  server  security  grade for ephemeral ellip-
+              The Postfix SMTP server  security  grade  for  ephemeral  ellip-
               tic-curve Diffie-Hellman (EECDH) key exchange.
 
        <b><a href="postconf.5.html#tls_eecdh_strong_curve">tls_eecdh_strong_curve</a> (prime256v1)</b>
-              The elliptic curve used by the Postfix SMTP server for  sensibly
+              The  elliptic curve used by the Postfix SMTP server for sensibly
               strong ephemeral ECDH key exchange.
 
        <b><a href="postconf.5.html#tls_eecdh_ultra_curve">tls_eecdh_ultra_curve</a> (secp384r1)</b>
@@ -583,7 +589,7 @@ SMTPD(8)                                                              SMTPD(8)
 
        <b><a href="postconf.5.html#tls_preempt_cipherlist">tls_preempt_cipherlist</a> (no)</b>
               With SSLv3 and later, use the Postfix SMTP server's cipher pref-
-              erence  order  instead  of the remote client's cipher preference
+              erence order instead of the remote  client's  cipher  preference
               order.
 
        <b><a href="postconf.5.html#tls_disable_workarounds">tls_disable_workarounds</a> (see 'postconf -d' output)</b>
@@ -596,7 +602,7 @@ SMTPD(8)                                                              SMTPD(8)
 
        Available in Postfix version 3.0 and later:
 
-       <b><a href="postconf.5.html#tls_session_ticket_cipher">tls_session_ticket_cipher</a> (Postfix</b> &gt;<b>= 3.0: aes-256-cbc, Postfix</b> &lt;  <b>3.0:</b>
+       <b><a href="postconf.5.html#tls_session_ticket_cipher">tls_session_ticket_cipher</a>  (Postfix</b> &gt;<b>= 3.0: aes-256-cbc, Postfix</b> &lt; <b>3.0:</b>
        <b>aes-128-cbc)</b>
               Algorithm used to encrypt <a href="https://tools.ietf.org/html/rfc5077">RFC5077</a> TLS session tickets.
 
@@ -609,26 +615,20 @@ SMTPD(8)                                                              SMTPD(8)
        Available in Postfix version 3.4 and later:
 
        <b><a href="postconf.5.html#smtpd_tls_chain_files">smtpd_tls_chain_files</a> (empty)</b>
-              List  of one or more PEM files, each holding one or more private
+              List of one or more PEM files, each holding one or more  private
               keys directly followed by a corresponding certificate chain.
 
        <b><a href="postconf.5.html#tls_server_sni_maps">tls_server_sni_maps</a> (empty)</b>
-              Optional lookup tables that map names received from remote  SMTP
-              clients  via  the  TLS Server Name Indication (SNI) extension to
+              Optional  lookup tables that map names received from remote SMTP
+              clients via the TLS Server Name Indication  (SNI)  extension  to
               the appropriate keys and certificate chains.
 
        Available in Postfix 3.5, 3.4.6, 3.3.5, 3.2.10, 3.1.13 and later:
 
        <b><a href="postconf.5.html#tls_fast_shutdown_enable">tls_fast_shutdown_enable</a> (yes)</b>
-              A workaround for implementations that hang Postfix  while  shut-
+              A  workaround  for implementations that hang Postfix while shut-
               ting down a TLS session, until Postfix times out.
 
-       Available in Postfix 3.5 and later:
-
-       <b><a href="postconf.5.html#info_log_address_format">info_log_address_format</a> (external)</b>
-              The  email  address  form that will be used in non-debug logging
-              (info, warning, etc.).
-
        Available in Postfix version 3.8 and later:
 
        <b><a href="postconf.5.html#tls_ffdhe_auto_groups">tls_ffdhe_auto_groups</a> (see 'postconf -d' output)</b>
index 54b72aba25a596e851c6fc0e1944b5995728fa60..1e22a03d9e58bab92787c4381723bdf760c9164b 100644 (file)
@@ -243,6 +243,8 @@ seconds. Report whether the session is re\-used. Retry if a new server
 is encountered, up to 5 times or as specified with the \fB\-m\fR option.
 By default reconnection is disabled, specify a positive delay to
 enable this behavior.
+.IP "\fB\-R\fR"
+Use SRV lookup instead of MX.
 .IP "\fB\-s \fIservername\fR"
 The server name to send with the TLS Server Name Indication (SNI)
 extension.  When the server has DANE TLSA records, this parameter
index a86e73363bae62588015b040243360f7ca239a33..3eeb9388ffd6a3a26968811c39b10dfea8a99c7e 100644 (file)
@@ -468,6 +468,11 @@ allow_percent_hack = no
 .fi
 .ad
 .ft R
+.SH allow_srv_lookup_fallback (default: no)
+When SRV record lookup fails or no SRV record exists, fall back
+to MX or IP address lookup as if SRV record lookup was not enabled.
+.PP
+This feature is available in Postfix 3.8 and later.
 .SH allow_untrusted_routing (default: no)
 Forward mail with sender\-specified routing (user[@%!]remote[@%!]site)
 from untrusted clients to destinations matching $relay_domains.
@@ -568,7 +573,7 @@ addresses that have no ".domain" information. With remotely submitted
 mail, append the string ".$remote_header_rewrite_domain"
 instead.
 .PP
-Note 1: this feature is enabled by default. If disabled, users will not be
+Note 1: When disabled (Postfix 3.0 and later), users will not be
 able to send mail to "user@partialdomainname" but will have to
 specify full domain names instead.
 .PP
@@ -2543,6 +2548,11 @@ delay.  This behavior is required by the SMTP standard.
 Specify "ignore_mx_lookup_error = yes" to force a DNS A record
 lookup instead. This violates the SMTP standard and can result in
 mis\-delivery of mail.
+.SH ignore_srv_lookup_error (default: no)
+When SRV record lookup fails, fall back to MX or IP address
+lookup as if SRV record lookup was not enabled. </>
+.PP
+This feature is available in Postfix 3.8 and later.
 .SH import_environment (default: see "postconf \-d" output)
 The list of environment variables that a privileged Postfix
 process will import from a non\-Postfix parent process, or name=value
@@ -14934,6 +14944,115 @@ for opportunities to reject mail, and defers the client request
 only if it would otherwise be accepted.
 .PP
 This feature is available in Postfix 2.6 and later.
+.SH use_srv_lookup (default: empty)
+Enables discovery for the specified service(s) using DNS SRV
+records. For example, with "use_srv_lookup = submission" and
+"relayhost = example.com:submission", the Postfix SMTP client will
+look up DNS SRV records for _submission._tcp.example.com, and will
+relay email through the hosts and ports that are specified with
+those records. See RFC 2782 for details of the host selection
+process.
+.PP
+Specify zero or more service names separated by comma and/or
+whitespace. Any name in the \fBservices\fR(5) database may be specified,
+though in practice only submission, submissions, and smtp make
+sense.
+.PP
+When SRV record lookup is enabled with use_srv_lookup, you can
+enclose a domain name in "[]" to force IP address lookup instead
+of SRV record lookup.
+.PP
+Example 1: MUA\-to\-MTA submission using SRV record lookup for
+the "submission" service for domain "example.com". This uses the
+default SMTP delivery agent with STARTTLS, and looks up SRV records
+for "_submission._tcp.example.com".
+.PP
+.nf
+.na
+.ft C
+/etc/postfix/main.cf:
+    use_srv_lookup = submission
+    relayhost = example.com:submission
+    smtp_tls_security_level = may
+    ...see SASL_README for sasl configuration...
+.fi
+.ad
+.ft R
+.PP
+Example 2: MUA\-to\-MTA submission using SRV record lookup for
+the "submissions" service for domain "example.org". This uses a
+dedicated SMTP delivery agent (smtp\-wraptls) with tls_wrappermode
+turned on, and looks up SRV records for "_submissions._tcp.example.org".
+.PP
+Note: specify the older name "smtps" instead of "submissions"
+when a provider has DNS SRV records like "_smtps._tcp.example.org"
+instead of "_submissions._tcp.example.org".
+.PP
+.nf
+.na
+.ft C
+/etc/postfix/main.cf:
+    use_srv_lookup = submissions
+    default_transport = smtp\-wraptls:example.org:submissions
+    ...see SASL_README for sasl configuration...
+.fi
+.ad
+.ft R
+.PP
+.nf
+.na
+.ft C
+/etc/postfix/master.cf:
+    smtp\-wraptls   unix   ...   ...   ...   ...   ...   smtp
+        \-o { smtp_tls_wrappermode = yes }
+        \-o { smtp_tls_security_level = encrypt }
+.fi
+.ad
+.ft R
+.PP
+Example 3: Sender\-dependent selection for a combination of
+MUA\-to\-MTA submission services. This combines examples 1 and 2 with
+examples of how to disable SRV and look up IP address records for
+"smtp\-relay.example.net" and "smtp\-relay.other.example".  Again,
+specify the older name "smtps" instead of "submissions" when a
+provider has DNS SRV records like "_smtps._tcp.example.org" instead
+of "_submissions._tcp.example.org".
+.PP
+.nf
+.na
+.ft C
+/etc/postfix/main.cf:
+    use_srv_lookup = submission, submissions
+    sender_dependent_default_transport_maps = inline:{
+        # Destinations that support SRV record lookup.
+        { user1@example.com = smtp:example.com:submission }
+        { user2@example.org = smtp\-wraptls:example.org:submissions }
+        # Use [destination] to force IP address lookups.
+        { user3@example.net = smtp:[smtp\-relay.example.net]:submission }
+        { user4@other.example =
+              smtp\-wraptls:[smtp\-relay.other.example]:submissions } }
+    ...see SASL_README for sasl configuration...
+.fi
+.ad
+.ft R
+.PP
+Example 4: MTA\-to\-MTA traffic, using SRV record lookup for the
+SMTP service. This is useful for Postfix tests, and may be useful
+in environments where ports are dynamically assigned to servers.
+.PP
+.nf
+.na
+.ft C
+/etc/postfix/main.cf:
+    use_srv_lookup = smtp
+    # Fall back to MX record lookup when SRV records are unavailable.
+    #allow_srv_lookup_fallback = yes
+    #ignore_srv_lookup_error = yes
+.fi
+.ad
+.ft R
+.PP
+This feature is available in Postfix 3.8 and later.
 .SH verp_delimiter_filter (default: \-=+)
 The characters Postfix accepts as VERP delimiter characters on the
 Postfix \fBsendmail\fR(1) command line and in SMTP commands.
index fa6138d7f8ab9e31556ead42a555d5ee1fd4f3ae..d2a4ce9ba89006ae7d245ea97fb92d299013b1ba 100644 (file)
@@ -164,6 +164,7 @@ RFC 2045 (MIME: Format of Internet Message Bodies)
 RFC 2046 (MIME: Media Types)
 RFC 2554 (AUTH command)
 RFC 2821 (SMTP protocol)
+RFC 2782 (SRV resource records)
 RFC 2920 (SMTP Pipelining)
 RFC 3207 (STARTTLS command)
 RFC 3461 (SMTP DSN Extension)
@@ -378,6 +379,17 @@ The minimum plaintext data transfer rate in bytes/second for
 DATA requests, when deadlines are enabled with smtp_per_request_deadline.
 .IP "\fBheader_from_format (standard)\fR"
 The format of the Postfix\-generated \fBFrom:\fR header.
+.PP
+Available in Postfix version 3.8 and later:
+.IP "\fBuse_srv_lookup (empty)\fR"
+Enables discovery for the specified service(s) using DNS SRV
+records.
+.IP "\fBignore_srv_lookup_error (no)\fR"
+When SRV record lookup fails, fall back to MX or IP address
+lookup as if SRV record lookups were not enabled.
+.IP "\fBallow_srv_lookup_fallback (no)\fR"
+When SRV record lookup fails or no SRV record exists, fall back
+to MX or IP address lookup as if SRV record lookups were not enabled.
 .SH "MIME PROCESSING CONTROLS"
 .na
 .nf
index bc8ec35a500d3f933e433c1ff763c2229d76b1f1..460293901e8f95534954ab8f0de5248dcc7919dc 100644 (file)
@@ -161,6 +161,11 @@ Available in Postfix version 3.0 and later:
 .IP "\fBsmtpd_dns_reply_filter (empty)\fR"
 Optional filter for Postfix SMTP server DNS lookup results.
 .PP
+Available in Postfix 3.5 and later:
+.IP "\fBinfo_log_address_format (external)\fR"
+The email address form that will be used in non\-debug logging
+(info, warning, etc.).
+.PP
 Available in Postfix version 3.6 and later:
 .IP "\fBsmtpd_relay_before_recipient_restrictions (see 'postconf -d' output)\fR"
 Evaluate smtpd_relay_restrictions before smtpd_recipient_restrictions.
@@ -552,11 +557,6 @@ Available in Postfix 3.5, 3.4.6, 3.3.5, 3.2.10, 3.1.13 and later:
 A workaround for implementations that hang Postfix while shutting
 down a TLS session, until Postfix times out.
 .PP
-Available in Postfix 3.5 and later:
-.IP "\fBinfo_log_address_format (external)\fR"
-The email address form that will be used in non\-debug logging
-(info, warning, etc.).
-.PP
 Available in Postfix version 3.8 and later:
 .IP "\fBtls_ffdhe_auto_groups (see 'postconf -d' output)\fR"
 The prioritized list of finite\-field Diffie\-Hellman ephemeral
index 3e07222a259fb832158f51966e2cc3c1e0fc6916..39057abe5c0bd366f7c610845b7fa8f97afacbd6 100755 (executable)
@@ -1157,6 +1157,10 @@ while (<>) {
     s;\blocal_login_sender_maps\b;<a href="postconf.5.html#local_login_sender_maps">$&</a>;g;
     s;\bempty_address_local_login_sender_maps_lookup_key\b;<a href="postconf.5.html#empty_address_local_login_sender_maps_lookup_key">$&</a>;g;
 
+    s;\buse_srv_lookup\b;<a href="postconf.5.html#use_srv_lookup">$&</a>;g;
+    s;\ballow_srv_lookup_fallback\b;<a href="postconf.5.html#allow_srv_lookup_fallback">$&</a>;g;
+    s;\bignore_srv_lookup_error\b;<a href="postconf.5.html#ignore_srv_lookup_error">$&</a>;g;
+
     # Service-defined parameters...
 
     s;\bpolicy_time_limit\b;<a href="postconf.5.html#transport_time_limit">$&</a>;g;
index 3e2025a7a14a9db724c76e0f70477ecb912a3b38..0b33f300964ddd0e29532136311f67fa519a16e0 100644 (file)
@@ -267,7 +267,7 @@ in <code>/usr/lib/sasl2/</code>. </p> </li>
 <li> <p> Cyrus SASL version 2.1.22 and newer additionally search
 in <code>/etc/sasl2/</code>. </p> </li>
 
-li> <p> With Postfix 2.5 and later you can explicitly configure the
+<li> <p> With Postfix 2.5 and later you can explicitly configure the
 search path via the <code>cyrus_sasl_config_path</code> configuration
 parameter. Specify zero or more colon-separated directories. If
 set empty (the default value) the search path is the one compiled
index a130f95fcce83e729187479545805667f9ae6499..be367b427456c0dc4efd59b1c0c7e959f0822f8c 100644 (file)
@@ -7380,7 +7380,7 @@ instead.
 </p>
 
 <p>
-Note 1: this feature is enabled by default. If disabled, users will not be
+Note 1: When disabled (Postfix 3.0 and later), users will not be
 able to send mail to "user@partialdomainname" but will have to
 specify full domain names instead.
 </p>
@@ -18478,3 +18478,110 @@ Postfix SMTP client will continue delivery after logging a warning.
 configuration parameter. See there for details. </p>
 
 <p> This feature is available in Postfix 3.7 and later. </p>
+
+%PARAM use_srv_lookup
+
+<p> Enables discovery for the specified service(s) using DNS SRV
+records. For example, with "use_srv_lookup = submission" and
+"relayhost = example.com:submission", the Postfix SMTP client will
+look up DNS SRV records for _submission._tcp.example.com, and will
+relay email through the hosts and ports that are specified with
+those records. See RFC 2782 for details of the host selection
+process. </p>
+
+<p> Specify zero or more service names separated by comma and/or
+whitespace. Any name in the services(5) database may be specified,
+though in practice only submission, submissions, and smtp make
+sense.  </p>
+
+<p> When SRV record lookup is enabled with use_srv_lookup, you can
+enclose a domain name in "[]" to force IP address lookup instead
+of SRV record lookup. </p>
+
+<p> Example 1: MUA-to-MTA submission using SRV record lookup for
+the "submission" service for domain "example.com". This uses the
+default SMTP delivery agent with STARTTLS, and looks up SRV records
+for "_submission._tcp.example.com". </p>
+
+<pre>
+/etc/postfix/main.cf:
+    use_srv_lookup = submission
+    relayhost = example.com:submission
+    smtp_tls_security_level = may
+    ...see SASL_README for sasl configuration...
+</pre>
+
+<p> Example 2: MUA-to-MTA submission using SRV record lookup for
+the "submissions" service for domain "example.org". This uses a
+dedicated SMTP delivery agent (smtp-wraptls) with tls_wrappermode
+turned on, and looks up SRV records for "_submissions._tcp.example.org".
+</p>
+
+<p> Note: specify the older name "smtps" instead of "submissions"
+when a provider has DNS SRV records like "_smtps._tcp.example.org"
+instead of "_submissions._tcp.example.org". </p>
+
+<pre>
+/etc/postfix/main.cf:
+    use_srv_lookup = submissions
+    default_transport = smtp-wraptls:example.org:submissions
+    ...see SASL_README for sasl configuration...
+</pre>
+
+<pre>
+/etc/postfix/master.cf:
+    smtp-wraptls   unix   ...   ...   ...   ...   ...   smtp
+        -o { smtp_tls_wrappermode = yes }
+        -o { smtp_tls_security_level = encrypt }
+</pre>
+
+<p> Example 3: Sender-dependent selection for a combination of
+MUA-to-MTA submission services. This combines examples 1 and 2 with
+examples of how to disable SRV and look up IP address records for
+"smtp-relay.example.net" and "smtp-relay.other.example".  Again,
+specify the older name "smtps" instead of "submissions" when a
+provider has DNS SRV records like "_smtps._tcp.example.org" instead
+of "_submissions._tcp.example.org". </p>
+
+<pre>
+/etc/postfix/main.cf:
+    use_srv_lookup = submission, submissions
+    sender_dependent_default_transport_maps = inline:{
+        # Destinations that support SRV record lookup.
+        { user1@example.com = smtp:example.com:submission }
+        { user2@example.org = smtp-wraptls:example.org:submissions }
+        # Use [destination] to force IP address lookups.
+        { user3@example.net = smtp:[smtp-relay.example.net]:submission }
+        { user4@other.example =
+              smtp-wraptls:[smtp-relay.other.example]:submissions } }
+    ...see SASL_README for sasl configuration...
+</pre>
+
+<p> Example 4: MTA-to-MTA traffic, using SRV record lookup for the
+SMTP service. This is useful for Postfix tests, and may be useful
+in environments where ports are dynamically assigned to servers.
+</p>
+
+<pre>
+/etc/postfix/main.cf:
+    use_srv_lookup = smtp
+    # Fall back to MX record lookup when SRV records are unavailable.
+    #allow_srv_lookup_fallback = yes
+    #ignore_srv_lookup_error = yes
+</pre>
+
+<p> This feature is available in Postfix 3.8 and later. </p>
+
+%PARAM ignore_srv_lookup_error no
+
+<p> When SRV record lookup fails, fall back to MX or IP address
+lookup as if SRV record lookup was not enabled. </>
+
+<p> This feature is available in Postfix 3.8 and later. </p>
+
+%PARAM allow_srv_lookup_fallback no
+
+<p> When SRV record lookup fails or no SRV record exists, fall back
+to MX or IP address lookup as if SRV record lookup was not enabled. <p>
+
+<p> This feature is available in Postfix 3.8 and later. </p>
index d663ad9c038eb131b711e974322c4816241a1fb3..d8dbb3a577bb82098d27122dfacc3d12ddf1b7d6 100644 (file)
@@ -1570,3 +1570,4 @@ Bugfix
 https
 egrep
 fgrep
+SRV
index 072374f681d06b384b424c4f450884e4f61fe260..425aa26bf6855f24ca10755bed37f9ae3c0e2dc1 100644 (file)
  src tls tls h src tls tls_proxy_client_misc c src tls tls_misc c 
  src global mail_params h src smtp smtp c 
  attacks Fix by Viktor Dukhovni Files tls tls h tls_client c 
+ proto stop spell proto html dns dns h dns dns_lookup c 
+ smtp smtp_addr h smtp smtp c smtp smtp_connect c 
+ smtp smtp h smtp smtp_params c smtp smtp_session c 
+ File smtpd smtpd c 
+ smtp smtp_addr c smtp smtp_addr h smtp smtp c 
+ smtp smtp_connect c smtp smtp h smtp smtp_params c 
+ arguments Files src dns dns h src dns dns_rr_eq_sa c 
+ only a subset of all arguments Files src dns dns h 
index a7e78243d531235f561bbb9f3a09531377b87991..c216f9598a80f1f1a7387ce19ab78952b8b024ee 100644 (file)
@@ -245,3 +245,4 @@ dt  dt b name value b Postfix ge 3 0 dt
  dt dt dd 4 Also log the hexadecimal and ASCII dump of complete
  parametername stress something something Other
  p Note on OpenBSD systems specify dev dev arandom when dev dev urandom
+ user3 example net smtp smtp relay example net submission 
index 9eb8f8a7e58268ac02f822de52b073d90fe169d5..b1fce0d3b61a550e489d3acb0ab82832395dfb45 100644 (file)
@@ -1789,3 +1789,7 @@ deduplicate
 digestbyname
 mdctxPtr
 ffdhe
+Korbar
+ign
+noport
+nopref
index 56e38baf72597b28909676d81385c4a3e43b0664..46e64559b75d927892707bfd05166f17e52fbf9c 100644 (file)
@@ -40,3 +40,7 @@ Typofixes
 segfault
 Biggs
 wordsmithing
+NOPORT
+NOPREF
+NOWEIGHT
+modernisms
index 7a0806880d630a4ec6fdcebe4c3f4864f36ca683..6d0cb20c764de3a28ac95a29d9d1b984a15f5083 100644 (file)
@@ -354,3 +354,5 @@ FFDHE
 dhe
 ffdhe
 kDHE
+srv
+wraptls
index 5f53dbc8ffaf3ed09f770b4d1ec9c9f3dc5c5423..acc1fb02951baa9c232b9a563cf6a10889a3a9f7 100644 (file)
@@ -158,7 +158,9 @@ typedef struct DNS_RR {
     unsigned short class;              /* C_IN, etc. */
     unsigned int ttl;                  /* always */
     unsigned int dnssec_valid;         /* DNSSEC validated */
-    unsigned short pref;               /* T_MX only */
+    unsigned short pref;               /* T_MX and T_SRV record related */
+    unsigned short weight;             /* T_SRV related, defined in rfc2782 */
+    unsigned short port;               /* T_SRV related, defined in rfc2782 */
     struct DNS_RR *next;               /* linkage */
     size_t  data_len;                  /* actual data size */
     char    data[1];                   /* actually a bunch of data */
@@ -183,14 +185,29 @@ extern char *dns_strrecord(VSTRING *, DNS_RR *);
  /*
   * dns_rr.c
   */
+#define DNS_RR_NOPREF  (0)
+#define DNS_RR_NOWEIGHT        (0)
+#define DNS_RR_NOPORT  (0)
+
+#define dns_rr_create_noport(qname, rname, type, class, ttl, pref, data, \
+                               data_len) \
+       dns_rr_create((qname), (rname), (type), (class), (ttl), \
+       (pref), DNS_RR_NOWEIGHT, DNS_RR_NOPORT, (data), (data_len))
+
+#define dns_rr_create_nopref(qname, rname, type, class, ttl, data, data_len) \
+       dns_rr_create_noport((qname), (rname), (type), (class), (ttl), \
+       DNS_RR_NOPREF, (data), (data_len))
+
 extern DNS_RR *dns_rr_create(const char *, const char *,
                                     ushort, ushort,
                                     unsigned, unsigned,
+                                    unsigned, unsigned,
                                     const char *, size_t);
 extern void dns_rr_free(DNS_RR *);
 extern DNS_RR *dns_rr_copy(DNS_RR *);
 extern DNS_RR *dns_rr_append(DNS_RR *, DNS_RR *);
 extern DNS_RR *dns_rr_sort(DNS_RR *, int (*) (DNS_RR *, DNS_RR *));
+extern DNS_RR *dns_srv_rr_sort(DNS_RR *);
 extern int dns_rr_compare_pref_ipv6(DNS_RR *, DNS_RR *);
 extern int dns_rr_compare_pref_ipv4(DNS_RR *, DNS_RR *);
 extern int dns_rr_compare_pref_any(DNS_RR *, DNS_RR *);
@@ -295,8 +312,9 @@ extern int dns_get_h_errno(void);
   * Below is the precedence order. The order between DNS_RETRY and DNS_NOTFOUND
   * is arbitrary.
   */
-#define DNS_RECURSE    (-7)            /* internal only: recursion needed */
-#define DNS_NOTFOUND   (-6)            /* query ok, data not found */
+#define DNS_RECURSE    (-8)            /* internal only: recursion needed */
+#define DNS_NOTFOUND   (-7)            /* query ok, data not found */
+#define DNS_NULLSRV    (-6)            /* query ok, service unavailable */
 #define DNS_NULLMX     (-5)            /* query ok, service unavailable */
 #define DNS_FAIL       (-4)            /* query failed, don't retry */
 #define DNS_INVAL      (-3)            /* query ok, malformed reply */
index 1c12a889dd247add6e29b371408dbd8fd8c97d63..d44cae7ee18a282fb995ea0437e17b96330af64f 100644 (file)
 /*     Google, Inc.
 /*     111 8th Avenue
 /*     New York, NY 10011, USA
+/*
+/*     SRV Support by
+/*     Tomas Korbar
+/*     Red Hat, Inc.
 /*--*/
 
 /* System library. */
@@ -295,8 +299,8 @@ typedef struct DNS_REPLY {
 #define INET6_ADDR_LEN 16              /* XXX */
 
  /*
-  * Use the threadsafe resolver API if available, not because it is theadsafe,
-  * but because it has more functionality.
+  * Use the threadsafe resolver API if available, not because it is
+  * theadsafe, but because it has more functionality.
   */
 #ifdef USE_RES_NCALLS
 static struct __res_state dns_res_state;
@@ -740,6 +744,8 @@ static int dns_get_rr(DNS_RR **list, const char *orig_name, DNS_REPLY *reply,
     int     comp_len;
     ssize_t data_len;
     unsigned pref = 0;
+    unsigned weight = 0;
+    unsigned port = 0;
     unsigned char *src;
     unsigned char *dst;
     int     ch;
@@ -765,6 +771,18 @@ static int dns_get_rr(DNS_RR **list, const char *orig_name, DNS_REPLY *reply,
            return (DNS_INVAL);
        data_len = strlen(temp) + 1;
        break;
+    case T_SRV:
+       GETSHORT(pref, pos);
+       GETSHORT(weight, pos);
+       GETSHORT(port, pos);
+       if (dn_expand(reply->buf, reply->end, pos, temp, sizeof(temp)) < 0)
+           return (DNS_RETRY);
+       if (*temp == 0)
+           return (DNS_NULLSRV);
+       if (!valid_rr_name(temp, "resource data", fixed->type, reply))
+           return (DNS_INVAL);
+       data_len = strlen(temp) + 1;
+       break;
     case T_MX:
        GETSHORT(pref, pos);
        if (dn_expand(reply->buf, reply->end, pos, temp, sizeof(temp)) < 0)
@@ -860,7 +878,7 @@ static int dns_get_rr(DNS_RR **list, const char *orig_name, DNS_REPLY *reply,
        break;
     }
     *list = dns_rr_create(orig_name, rr_name, fixed->type, fixed->class,
-                         fixed->ttl, pref, tempbuf, data_len);
+                         fixed->ttl, pref, weight, port, tempbuf, data_len);
     return (DNS_OK);
 }
 
@@ -960,7 +978,7 @@ static int dns_get_answer(const char *orig_name, DNS_REPLY *reply, int type,
                    resource_found++;
                    rr->dnssec_valid = *maybe_secure ? reply->dnssec_ad : 0;
                    *rrlist = dns_rr_append(*rrlist, rr);
-               } else if (status == DNS_NULLMX) {
+               } else if (status == DNS_NULLMX || status == DNS_NULLSRV) {
                    CORRUPT(status);            /* TODO: use better name */
                } else if (not_found_status != DNS_RETRY)
                    not_found_status = status;
@@ -1094,6 +1112,12 @@ int     dns_lookup_x(const char *name, unsigned type, unsigned flags,
                                name);
            DNS_SET_H_ERRNO(&dns_res_state, NO_DATA);
            return (status);
+       case DNS_NULLSRV:
+           if (why)
+               vstring_sprintf(why, "Domain %s does not support SRV requests",
+                               name);
+           DNS_SET_H_ERRNO(&dns_res_state, NO_DATA);
+           return (status);
        case DNS_OK:
            if (rrlist && dns_rr_filter_maps) {
                if (dns_rr_filter_execute(rrlist) < 0) {
index b550788b992277174ff733157d03c3b26d3bcfdf..803263599f520a5cd58db11d0b89fbbb65dbab22 100644 (file)
@@ -7,13 +7,15 @@
 /*     #include <dns.h>
 /*
 /*     DNS_RR  *dns_rr_create(qname, rname, type, class, ttl, preference,
-/*                             data, data_len)
+/*                             weight, port, data, data_len)
 /*     const char *qname;
 /*     const char *rname;
 /*     unsigned short type;
 /*     unsigned short class;
 /*     unsigned int ttl;
 /*     unsigned preference;
+/*     unsigned weight;
+/*     unsigned port;
 /*     const char *data;
 /*     size_t data_len;
 /*
 /*     DNS_RR  *dns_rr_remove(list, record)
 /*     DNS_RR  *list;
 /*     DNS_RR  *record;
+/*
+/*     DNS_RR  *dns_srv_rr_sort(list)
+/*     DNS_RR  *list;
+/* AUXILIARY FUNCTIONS
+/*     DNS_RR  *dns_rr_create_nopref(qname, rname, type, class, ttl,
+/*                                     data, data_len)
+/*     const char *qname;
+/*     const char *rname;
+/*     unsigned short type;
+/*     unsigned short class;
+/*     unsigned int ttl;
+/*     const char *data;
+/*     size_t data_len;
+/*
+/*     DNS_RR  *dns_rr_create_noport(qname, rname, type, class, ttl,
+/*                                     preference, data, data_len)
+/*     const char *qname;
+/*     const char *rname;
+/*     unsigned short type;
+/*     unsigned short class;
+/*     unsigned int ttl;
+/*     unsigned preference;
+/*     const char *data;
+/*     size_t data_len;
 /* DESCRIPTION
 /*     The routines in this module maintain memory for DNS resource record
 /*     information, and maintain lists of DNS resource records.
 /*     dns_rr_create() creates and initializes one resource record.
 /*     The \fIqname\fR field specifies the query name.
 /*     The \fIrname\fR field specifies the reply name.
-/*     \fIpreference\fR is used for MX records; \fIdata\fR is a null
+/*     \fIpreference\fR is used for MX and SRV records; \fIweight\fR
+/*     and \fIport\fR are used for SRV records; \fIdata\fR is a null
 /*     pointer or specifies optional resource-specific data;
 /*     \fIdata_len\fR is the amount of resource-specific data.
 /*
+/*     dns_rr_create_nopref() and dns_rr_create_noport() are convenience
+/*     wrappers around dns_rr_create() that take fewer arguments.
+/*
 /*     dns_rr_free() releases the resource used by of zero or more
 /*     resource records.
 /*
 /*     dns_rr_remove() removes the specified record from the specified list.
 /*     The updated list is the result value.
 /*     The record MUST be a list member.
+/*
+/*     dns_srv_rr_sort() sorts a list of SRV records according to
+/*     their priority and weight as described in RFC 2782.
 /* LICENSE
 /* .ad
 /* .fi
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
+/*
+/*     SRV Support by
+/*     Tomas Korbar
+/*     Red Hat, Inc.
 /*--*/
 
 /* System library. */
 DNS_RR *dns_rr_create(const char *qname, const char *rname,
                              ushort type, ushort class,
                              unsigned int ttl, unsigned pref,
+                             unsigned weight, unsigned port,
                              const char *data, size_t data_len)
 {
     DNS_RR *rr;
@@ -125,6 +168,8 @@ DNS_RR *dns_rr_create(const char *qname, const char *rname,
     rr->ttl = ttl;
     rr->dnssec_valid = 0;
     rr->pref = pref;
+    rr->weight = weight;
+    rr->port = port;
     if (data && data_len > 0)
        memcpy(rr->data, data, data_len);
     rr->data_len = data_len;
@@ -247,6 +292,12 @@ DNS_RR *dns_rr_sort(DNS_RR *list, int (*compar) (DNS_RR *, DNS_RR *))
     int     len;
     int     i;
 
+    /*
+     * Avoid mymalloc() panic.
+     */
+    if (list == 0)
+       return (list);
+
     /*
      * Save state and initialize.
      */
@@ -293,6 +344,12 @@ DNS_RR *dns_rr_shuffle(DNS_RR *list)
     int     i;
     int     r;
 
+    /*
+     * Avoid mymalloc() panic.
+     */
+    if (list == 0)
+       return (list);
+
     /*
      * Build linear array with pointers to each list element.
      */
@@ -345,3 +402,141 @@ DNS_RR *dns_rr_remove(DNS_RR *list, DNS_RR *record)
     }
     return (list);
 }
+
+/* weight_order - sort equal-priority records by weight */
+
+static void weight_order(DNS_RR **array, int count)
+{
+    int     unordered_weights;
+    int     i;
+
+    /*
+     * Compute the sum of record weights. If weights are not supplied then
+     * this function would be a noop. In fact this would be a noop when all
+     * weights have the same value, whether that weight is zero or not. There
+     * is no need to give special treatment to zero weights.
+     */
+    for (unordered_weights = 0, i = 0; i < count; i++)
+       unordered_weights += array[i]->weight;
+    if (unordered_weights == 0)
+       return;
+
+    /*
+     * The record ordering code below differs from RFC 2782 when the input
+     * contains a mix of zero and non-zero weights: the code below does not
+     * give special treatment to zero weights. Instead, it treats a zero
+     * weight just like any other small weight. Fewer special cases make for
+     * code that is simpler and more robust.
+     */
+    for (i = 0; i < count - 1; i++) {
+       int     running_sum;
+       int     threshold;
+       int     k;
+       DNS_RR *temp;
+
+       /*
+        * Choose a random threshold [0..unordered_weights] inclusive.
+        */
+       threshold = myrand() % (unordered_weights + 1);
+
+       /*
+        * Move the first record with running_sum >= threshold to the ordered
+        * list, and update unordered_weights.
+        */
+       for (running_sum = 0, k = i; k < count; k++) {
+           running_sum += array[k]->weight;
+           if (running_sum >= threshold) {
+               unordered_weights -= array[k]->weight;
+               temp = array[i];
+               array[i] = array[k];
+               array[k] = temp;
+               break;
+           }
+       }
+    }
+}
+
+/* dns_srv_rr_sort - sort resource record list */
+
+DNS_RR *dns_srv_rr_sort(DNS_RR *list)
+{
+    int     (*saved_user) (DNS_RR *, DNS_RR *);
+    DNS_RR **rr_array;
+    DNS_RR *rr;
+    int     len;
+    int     i;
+    int     r;
+    int     cur_pref;
+    int     left_bound;                        /* inclusive */
+    int     right_bound;               /* non-inclusive */
+
+    /*
+     * Avoid mymalloc() panic, or rr_array[0] fence-post error.
+     */
+    if (list == 0)
+       return (list);
+
+    /*
+     * Save state and initialize.
+     */
+    saved_user = dns_rr_sort_user;
+    dns_rr_sort_user = dns_rr_compare_pref_any;
+
+    /*
+     * Build linear array with pointers to each list element.
+     */
+    for (len = 0, rr = list; rr != 0; len++, rr = rr->next)
+        /* void */ ;
+    rr_array = (DNS_RR **) mymalloc(len * sizeof(*rr_array));
+    for (len = 0, rr = list; rr != 0; len++, rr = rr->next)
+       rr_array[len] = rr;
+
+    /*
+     * Shuffle resource records. Every element has an equal chance of landing
+     * in slot 0.  After that every remaining element has an equal chance of
+     * landing in slot 1, ...  This is exactly n! states for n! permutations.
+     */
+    for (i = 0; i < len - 1; i++) {
+       r = i + (myrand() % (len - i));         /* Victor&Son */
+       rr = rr_array[i];
+       rr_array[i] = rr_array[r];
+       rr_array[r] = rr;
+    }
+
+    /* First order the records by preference. */
+    qsort((void *) rr_array, len, sizeof(*rr_array), dns_rr_sort_callback);
+
+    /*
+     * Walk through records and sort the records in every same-preference
+     * partition according to their weight. Note that left_bound is
+     * inclusive, and that right-bound is non-inclusive.
+     */
+    left_bound = 0;
+    cur_pref = rr_array[left_bound]->pref;     /* assumes len > 0 */
+
+    for (right_bound = 1; /* see below */ ; right_bound++) {
+       if (right_bound == len || rr_array[right_bound]->pref != cur_pref) {
+           if (right_bound - left_bound > 1)
+               weight_order(rr_array + left_bound, right_bound - left_bound);
+           if (right_bound == len)
+               break;
+           left_bound = right_bound;
+           cur_pref = rr_array[left_bound]->pref;
+       }
+    }
+
+    /*
+     * Fix the links.
+     */
+    for (i = 0; i < len - 1; i++)
+       rr_array[i]->next = rr_array[i + 1];
+    rr_array[i]->next = 0;
+    list = rr_array[0];
+
+    /*
+     * Cleanup.
+     */
+    myfree((void *) rr_array);
+    dns_rr_sort_user = saved_user;
+    return (list);
+}
index 8113d6b26d6b258f2356fb567a1ad2697ad56fb9..f553a032317fdc91785bae85c3d37687b082a8c4 100644 (file)
@@ -122,7 +122,7 @@ int     main(int argc, char **argv)
 
        if ((aierr = hostaddr_to_sockaddr(argv[1], (char *) 0, 0, &res1)) != 0)
            msg_fatal("host address %s: %s", argv[1], MAI_STRERROR(aierr));
-       if ((rr = dns_sa_to_rr(argv[1], 0, res1->ai_addr)) == 0)
+       if ((rr = dns_sa_to_rr(argv[1], DNS_RR_NOPREF, res1->ai_addr)) == 0)
            msg_fatal("dns_sa_to_rr: %m");
        freeaddrinfo(res1);
 
index 6b9efcc170ffd82c4e39c267222a7835f40844d6..b5dee20914659b18664ca3fc55c8df0cf2a1d76f 100644 (file)
@@ -55,14 +55,14 @@ DNS_RR *dns_sa_to_rr(const char *hostname, unsigned pref, struct sockaddr *sa)
 #define DUMMY_TTL      0
 
     if (sa->sa_family == AF_INET) {
-       return (dns_rr_create(hostname, hostname, T_A, C_IN, DUMMY_TTL, pref,
-                             (char *) &SOCK_ADDR_IN_ADDR(sa),
-                             sizeof(SOCK_ADDR_IN_ADDR(sa))));
+       return (dns_rr_create_noport(hostname, hostname, T_A, C_IN, DUMMY_TTL,
+                                    pref, (char *) &SOCK_ADDR_IN_ADDR(sa),
+                                    sizeof(SOCK_ADDR_IN_ADDR(sa))));
 #ifdef HAS_IPV6
     } else if (sa->sa_family == AF_INET6) {
-       return (dns_rr_create(hostname, hostname, T_AAAA, C_IN, DUMMY_TTL, pref,
-                             (char *) &SOCK_ADDR_IN6_ADDR(sa),
-                             sizeof(SOCK_ADDR_IN6_ADDR(sa))));
+       return (dns_rr_create_noport(hostname, hostname, T_AAAA, C_IN, DUMMY_TTL,
+                                    pref, (char *) &SOCK_ADDR_IN6_ADDR(sa),
+                                    sizeof(SOCK_ADDR_IN6_ADDR(sa))));
 #endif
     } else {
        errno = EAFNOSUPPORT;
@@ -121,7 +121,7 @@ int     main(int argc, char **argv)
            resv[len++] = res;
        qsort((void *) resv, len, sizeof(*resv), compare_family);
        for (n = 0; n < len; n++) {
-           if ((rr = dns_sa_to_rr(argv[0], 0, resv[n]->ai_addr)) == 0)
+           if ((rr = dns_sa_to_rr(argv[0], DNS_RR_NOPREF, resv[n]->ai_addr)) == 0)
                msg_fatal("dns_sa_to_rr: %m");
            if (dns_rr_to_pa(rr, &hostaddr) == 0)
                msg_fatal("dns_rr_to_pa: %m");
index 472394c3a63554b0a761789e9d90d39381a5d06b..793da1c2610ca5b999b2e30ca45ea93a35e32950 100644 (file)
@@ -21,6 +21,8 @@
 /*     Google, Inc.
 /*     111 8th Avenue
 /*     New York, NY 10011, USA
+/*
+/*     Viktor Dukhovni
 /*--*/
 
  /*
 static const LONG_NAME_MASK resflag_table[] = {
     "RES_INIT", RES_INIT,
     "RES_DEBUG", RES_DEBUG,
-#ifdef RES_AAONLY
+#if defined(RES_AAONLY) && !HAVE_GLIBC_API_VERSION_SUPPORT(2, 24)
     "RES_AAONLY", RES_AAONLY,
 #endif
     "RES_USEVC", RES_USEVC,
-#ifdef RES_PRIMARY
+#if defined(RES_PRIMARY) && !HAVE_GLIBC_API_VERSION_SUPPORT(2, 24)
     "RES_PRIMARY", RES_PRIMARY,
 #endif
     "RES_IGNTC", RES_IGNTC,
@@ -77,15 +79,15 @@ static const LONG_NAME_MASK resflag_table[] = {
 #ifdef RES_ROTATE
     "RES_ROTATE", RES_ROTATE,
 #endif
-#ifdef RES_NOCHECKNAME
+#if defined(RES_NOCHECKNAME) && !HAVE_GLIBC_API_VERSION_SUPPORT(2, 24)
     "RES_NOCHECKNAME", RES_NOCHECKNAME,
 #endif
     "RES_USE_EDNS0", RES_USE_EDNS0,
     "RES_USE_DNSSEC", RES_USE_DNSSEC,
-#ifdef RES_KEEPTSIG
+#if defined(RES_KEEPTSIG) && !HAVE_GLIBC_API_VERSION_SUPPORT(2, 24)
     "RES_KEEPTSIG", RES_KEEPTSIG,
 #endif
-#ifdef RES_BLAST
+#if defined(RES_BLAST) && !HAVE_GLIBC_API_VERSION_SUPPORT(2, 24)
     "RES_BLAST", RES_BLAST,
 #endif
 #ifdef RES_USEBSTRING
index 6b8e9893eb9350deb509f2fa13fd8379d1bbe03f..1e3b74389353f9540c22485a198d1f19610cf00c 100644 (file)
@@ -80,6 +80,10 @@ char   *dns_strrecord(VSTRING *buf, DNS_RR *rr)
     case T_MX:
        vstring_sprintf_append(buf, "%u %s.", rr->pref, rr->data);
        break;
+    case T_SRV:
+       vstring_sprintf_append(buf, "%u %u %u %s.", rr->pref, rr->weight,
+                              rr->port, rr->data);
+       break;
     case T_TLSA:
        if (rr->data_len >= 3) {
            uint8_t *ip = (uint8_t *) rr->data;
index 70e59acdc128e83ac68fc1401bd23456128f4c26..7eebe3c08768f74cba9496d227076a04aea973a6 100644 (file)
@@ -180,6 +180,9 @@ static struct dns_type_map dns_type_map[] = {
 #ifdef T_ANY
     T_ANY, "ANY",
 #endif
+#ifdef T_SRV
+    T_SRV, "SRV",
+#endif
 };
 
 /* dns_strtype - translate DNS query type to string */
index 4df9b7b02db88382fe43ffdaf1e78d9bfc0f89da..b364850c552af73ea2a4c71ffa4e967edf03bfb5 100644 (file)
@@ -4364,6 +4364,21 @@ extern char *var_dnssec_probe;
                "lmtp=24, smtp=25, smtps=submissions=465, submission=587"
 extern char *var_known_tcp_ports;
 
+ /*
+  * SRV lookup support.
+  */
+#define VAR_USE_SRV_LOOKUP     "use_srv_lookup"
+#define DEF_USE_SRV_LOOKUP     ""
+extern char *var_use_srv_lookup;
+
+#define VAR_IGN_SRV_LOOKUP_ERR "ignore_srv_lookup_error"
+#define DEF_IGN_SRV_LOOKUP_ERR 0
+extern bool var_ign_srv_lookup_err;
+
+#define VAR_ALLOW_SRV_FALLBACK "allow_srv_lookup_fallback"
+#define DEF_ALLOW_SRV_FALLBACK 0
+extern bool var_allow_srv_fallback;
+
 /* LICENSE
 /* .ad
 /* .fi
index fcf78608ee7a8d313d7a1b573d48c9ed67e13903..d67ef3aacd005cd9dfaf96bd636d96cedbcc9bfa 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      "20230128"
+#define MAIL_RELEASE_DATE      "20230219"
 #define MAIL_VERSION_NUMBER    "3.8"
 
 #ifdef SNAPSHOT
index 5526c408d1f06c1d70a0faa9d756b68e58a8baff..2a9efe2db5c1c742b9fc0ccc4a3e2824cf57a90e 100644 (file)
 /*     is encountered, up to 5 times or as specified with the \fB-m\fR option.
 /*     By default reconnection is disabled, specify a positive delay to
 /*     enable this behavior.
+/* .IP "\fB-R\fR"
+/*     Use SRV lookup instead of MX.
 /* .IP "\fB-s \fIservername\fR"
 /*     The server name to send with the TLS Server Name Indication (SNI)
 /*     extension.  When the server has DANE TLSA records, this parameter
@@ -469,6 +471,7 @@ typedef struct STATE {
     DNS_RR *mx;                                /* MX RRset qname, rname, valid */
     int     pass;                      /* Pass number, 2 for reconnect */
     int     nochat;                    /* disable chat logging */
+    int     dosrv;                     /* look up SRV records instead of MX */
     char   *helo;                      /* Server name from EHLO reply */
     DSN_BUF *why;                      /* SMTP-style error message */
     VSTRING *buffer;                   /* Response buffer */
@@ -1159,7 +1162,7 @@ static VSTREAM *connect_addr(STATE *state, DNS_RR *addr)
 /* addr_one - address lookup for one host name */
 
 static DNS_RR *addr_one(STATE *state, DNS_RR *addr_list, const char *host,
-                               int res_opt, unsigned pref)
+                               int res_opt, unsigned pref, unsigned port)
 {
     static const char *myname = "addr_one";
     DSN_BUF *why = state->why;
@@ -1182,6 +1185,8 @@ static DNS_RR *addr_one(STATE *state, DNS_RR *addr_list, const char *host,
        if ((addr = dns_sa_to_rr(host, pref, res0->ai_addr)) == 0)
            msg_fatal("host %s: conversion error for address family %d: %m",
                    host, ((struct sockaddr *) (res0->ai_addr))->sa_family);
+       addr->pref = pref;
+       addr->port = port;
        addr_list = dns_rr_append(addr_list, addr);
        freeaddrinfo(res0);
        return (addr_list);
@@ -1198,8 +1203,10 @@ static DNS_RR *addr_one(STATE *state, DNS_RR *addr_list, const char *host,
                             why->reason, DNS_REQ_FLAG_NONE,
                             proto_info->dns_atype_list)) {
        case DNS_OK:
-           for (rr = addr; rr; rr = rr->next)
+           for (rr = addr; rr; rr = rr->next) {
                rr->pref = pref;
+               rr->port = port;
+           }
            addr_list = dns_rr_append(addr_list, addr);
            return (addr_list);
        default:
@@ -1286,15 +1293,15 @@ static DNS_RR *mx_addr_list(STATE *state, DNS_RR *mx_names)
 #endif
 
     for (rr = mx_names; rr; rr = rr->next) {
-       if (rr->type != T_MX)
+       if (rr->type != T_MX && rr->type != T_SRV)
            msg_panic("%s: bad resource type: %d", myname, rr->type);
        addr_list = addr_one(state, addr_list, (char *) rr->data, res_opt,
-                            rr->pref);
+                            rr->pref, rr->port);
     }
     return (addr_list);
 }
 
-/* smtp_domain_addr - mail exchanger address lookup */
+/* domain_addr - mail exchanger address lookup */
 
 static DNS_RR *domain_addr(STATE *state, char *domain)
 {
@@ -1359,6 +1366,74 @@ static DNS_RR *domain_addr(STATE *state, char *domain)
     return (addr_list);
 }
 
+/* service_addr - mail exchanger address lookup */
+
+static DNS_RR *service_addr(STATE *state, const char *domain,
+                                   const char *service)
+{
+    VSTRING *srv_qname = vstring_alloc(100);
+    char   *str_srv_qname;
+    DNS_RR *srv_names;
+    DNS_RR *addr_list = 0;
+    int     r = 0;                     /* Resolver flags */
+    const char *aname;
+
+    dsb_reset(state->why);
+
+#if (RES_USE_DNSSEC != 0) && (RES_USE_EDNS0 != 0)
+    r |= RES_USE_DNSSEC;
+#endif
+
+    vstring_sprintf(srv_qname, "_%s._tcp.%s", service, domain);
+    str_srv_qname = STR(srv_qname);
+
+    /*
+     * IDNA support.
+     */
+#ifndef NO_EAI
+    if (!allascii(str_srv_qname)
+       && (aname = midna_domain_to_ascii(str_srv_qname)) != 0) {
+       msg_info("%s asciified to %s", str_srv_qname, aname);
+    } else
+#endif
+       aname = str_srv_qname;
+
+    switch (dns_lookup(aname, T_SRV, r, &srv_names, (VSTRING *) 0,
+                      state->why->reason)) {
+    default:
+       dsb_status(state->why, "4.4.3");
+       break;
+    case DNS_INVAL:
+       dsb_status(state->why, "5.4.4");
+       break;
+    case DNS_NULLMX:
+       dsb_status(state->why, "5.1.0");
+       break;
+    case DNS_FAIL:
+       dsb_status(state->why, "5.4.3");
+       break;
+    case DNS_OK:
+       /* Shuffle then sort the SRV rr records by priority and weight. */
+       srv_names = dns_srv_rr_sort(srv_names);
+       addr_list = mx_addr_list(state, srv_names);
+       state->mx = dns_rr_copy(srv_names);
+       dns_rr_free(srv_names);
+       if (addr_list == 0) {
+           msg_warn("no SRV host for %s has a valid address record",
+                    str_srv_qname);
+           break;
+       }
+       /* TODO: sort by priority, weight, and address family preference. */
+       break;
+    case DNS_NOTFOUND:
+       dsb_status(state->why, "5.4.4");
+       break;
+    }
+
+    vstring_free(srv_qname);
+    return (addr_list);
+}
+
 /* host_addr - direct host lookup */
 
 static DNS_RR *host_addr(STATE *state, const char *host)
@@ -1385,7 +1460,8 @@ static DNS_RR *host_addr(STATE *state, const char *host)
        ahost = host;
 
 #define PREF0  0
-    addr_list = addr_one(state, (DNS_RR *) 0, ahost, res_opt, PREF0);
+#define NOPORT 0
+    addr_list = addr_one(state, (DNS_RR *) 0, ahost, res_opt, PREF0, NOPORT);
     if (addr_list && addr_list->next) {
        addr_list = dns_rr_shuffle(addr_list);
        if (inet_proto_info()->ai_family_list[1] != 0)
@@ -1469,7 +1545,8 @@ static int dane_host_level(STATE *state, DNS_RR *addr)
 /* parse_destination - parse host/port destination */
 
 static char *parse_destination(char *destination, char *def_service,
-                                      char **hostp, unsigned *portp)
+                                      char **hostp, char **servicep,
+                                      unsigned *portp)
 {
     char   *buf = mystrdup(destination);
     char   *service;
@@ -1485,13 +1562,13 @@ static char *parse_destination(char *destination, char *def_service,
      * Parse the host/port information. We're working with a copy of the
      * destination argument so the parsing can be destructive.
      */
-    if ((err = host_port(buf, hostp, (char *) 0, &service, def_service)) != 0)
+    if ((err = host_port(buf, hostp, (char *) 0, servicep, def_service)) != 0)
        msg_fatal("%s in server description: %s", err, destination);
 
     /*
      * Convert service to port number, network byte order.
      */
-    service = (char *) filter_known_tcp_port(service);
+    service = (char *) filter_known_tcp_port(*servicep);
     if (alldig(service)) {
        if ((port = atoi(service)) >= 65536 || port == 0)
            msg_fatal("bad network port: %s for destination: %s",
@@ -1515,15 +1592,18 @@ static void connect_remote(STATE *state, char *dest)
     DNS_RR *addr;
     char   *buf;
     char   *domain;
+    char   *service;
 
     /* When reconnecting use IP address of previous session */
     if (state->addr == 0) {
        buf = parse_destination(dest, state->smtp ? "smtp" : "24",
-                               &domain, &state->port);
+                               &domain, &service, &state->port);
        if (!state->nexthop)
            state->nexthop = mystrdup(domain);
        if (state->smtp == 0 || *dest == '[')
            state->addr = host_addr(state, domain);
+       else if (state->dosrv)
+           state->addr = service_addr(state, domain, service);
        else
            state->addr = domain_addr(state, domain);
        myfree(buf);
@@ -1537,10 +1617,14 @@ static void connect_remote(STATE *state, char *dest)
     for (addr = state->addr; addr; addr = addr->next) {
        int     level = dane_host_level(state, addr);
 
+       if (addr->port)                         /* SRV port override */
+           state->port = htons(addr->port);
+
        if (level == TLS_LEV_INVALID
            || (state->stream = connect_addr(state, addr)) == 0) {
-           msg_info("Failed to establish session to %s via %s: %s",
-                    dest, HNAME(addr), vstring_str(state->why->reason));
+           msg_info("Failed to establish session to %s:%s via %s:%u: %s",
+                    dest, service, HNAME(addr), addr->port,
+                    vstring_str(state->why->reason));
            continue;
        }
        /* We have a connection */
@@ -1808,6 +1892,7 @@ static void parse_options(STATE *state, int argc, char *argv[])
 
     state->smtp = 1;
     state->pass = 1;
+    state->dosrv = 0;
     state->reconnect = -1;
     state->max_reconnect = 5;
     state->wrapper_mode = 0;
@@ -1818,7 +1903,7 @@ static void parse_options(STATE *state, int argc, char *argv[])
     memset((void *) &state->options, 0, sizeof(state->options));
     state->options.host_lookup = mystrdup("dns");
 
-#define OPTS "a:ch:o:St:T:v"
+#define OPTS "a:ch:o:RSt:T:v"
 #ifdef USE_TLS
 #define TLSOPTS "A:Cd:fF:g:H:k:K:l:L:m:M:p:P:r:s:wX"
 
@@ -1857,6 +1942,9 @@ static void parse_options(STATE *state, int argc, char *argv[])
        case 'o':
            override(optarg);
            break;
+       case 'R':
+           state->dosrv = 1;
+           break;
        case 'S':
            state->smtp = 0;
            break;
index cc3364642d56197063fb8ba0be069a29eca9d7bc..bca7cd494b5ff522f4e9397e11c37316513e3fcb 100644 (file)
@@ -65,6 +65,7 @@
        VAR_LMTP_DNS_RE_FILTER, DEF_LMTP_DNS_RE_FILTER, &var_smtp_dns_re_filter, 0, 0,
        VAR_TLSPROXY_SERVICE, DEF_TLSPROXY_SERVICE, &var_tlsproxy_service, 1, 0,
        VAR_HFROM_FORMAT, DEF_HFROM_FORMAT, &var_hfrom_format, 1, 0,
+       VAR_USE_SRV_LOOKUP, DEF_USE_SRV_LOOKUP, &var_use_srv_lookup, 0, 0,
        0,
     };
     static const CONFIG_TIME_TABLE lmtp_time_table[] = {
        VAR_LMTP_DUMMY_MAIL_AUTH, DEF_LMTP_DUMMY_MAIL_AUTH, &var_smtp_dummy_mail_auth,
        VAR_LMTP_BALANCE_INET_PROTO, DEF_LMTP_BALANCE_INET_PROTO, &var_smtp_balance_inet_proto,
        VAR_LMTP_BIND_ADDR_ENFORCE, DEF_LMTP_BIND_ADDR_ENFORCE, &var_smtp_bind_addr_enforce,
+       VAR_IGN_SRV_LOOKUP_ERR, DEF_IGN_SRV_LOOKUP_ERR, &var_ign_srv_lookup_err,
+       VAR_ALLOW_SRV_FALLBACK, DEF_ALLOW_SRV_FALLBACK, &var_allow_srv_fallback,
        0,
     };
     static const CONFIG_NBOOL_TABLE lmtp_nbool_table[] = {
index a398dc5ae421c10e8111d12bb4bce815ba7bdce3..e865197ab5f20199038de6ccc8ed3536448094bf 100644 (file)
 /*     RFC 2046 (MIME: Media Types)
 /*     RFC 2554 (AUTH command)
 /*     RFC 2821 (SMTP protocol)
+/*     RFC 2782 (SRV resource records)
 /*     RFC 2920 (SMTP Pipelining)
 /*     RFC 3207 (STARTTLS command)
 /*     RFC 3461 (SMTP DSN Extension)
 /*     DATA requests, when deadlines are enabled with smtp_per_request_deadline.
 /* .IP "\fBheader_from_format (standard)\fR"
 /*     The format of the Postfix-generated \fBFrom:\fR header.
+/* .PP
+/*     Available in Postfix version 3.8 and later:
+/* .IP "\fBuse_srv_lookup (empty)\fR"
+/*     Enables discovery for the specified service(s) using DNS SRV
+/*     records.
+/* .IP "\fBignore_srv_lookup_error (no)\fR"
+/*     When SRV record lookup fails, fall back to MX or IP address
+/*     lookup as if SRV record lookups were not enabled.
+/* .IP "\fBallow_srv_lookup_fallback (no)\fR"
+/*     When SRV record lookup fails or no SRV record exists, fall back
+/*     to MX or IP address lookup as if SRV record lookups were not enabled.
 /* MIME PROCESSING CONTROLS
 /* .ad
 /* .fi
@@ -1095,6 +1107,9 @@ char   *var_smtp_dns_re_filter;
 bool    var_smtp_balance_inet_proto;
 bool    var_smtp_req_deadline;
 int     var_smtp_min_data_rate;
+char   *var_use_srv_lookup;
+bool   var_ign_srv_lookup_err;
+bool   var_allow_srv_fallback;
 
  /* Special handling of 535 AUTH errors. */
 char   *var_smtp_sasl_auth_cache_name;
@@ -1121,6 +1136,7 @@ HBC_CHECKS *smtp_header_checks;           /* limited header checks */
 HBC_CHECKS *smtp_body_checks;          /* limited body checks */
 SMTP_CLI_ATTR smtp_cli_attr;           /* parsed command-line */
 int     smtp_hfrom_format;             /* postmaster notifications */
+STRING_LIST *smtp_use_srv_lookup;
 
 #ifdef USE_TLS
 
@@ -1411,6 +1427,14 @@ static void post_init(char *unused_name, char **argv)
      * header_from format, for postmaster notifications.
      */
     smtp_hfrom_format = hfrom_format_parse(VAR_HFROM_FORMAT, var_hfrom_format);
+
+    /*
+     * Service discovery with SRV record lookup.
+     */
+    if (*var_use_srv_lookup)
+       smtp_use_srv_lookup = string_list_init(VAR_USE_SRV_LOOKUP,
+                                              MATCH_FLAG_RETURN,
+                                              var_use_srv_lookup);
 }
 
 /* pre_init - pre-jail initialization */
index 742ed300cc0ccd5e577c348e5dd65ad77f53ba88..0864313b764da70a471fdbc8c3c33f157e41360a 100644 (file)
@@ -84,6 +84,14 @@ typedef struct SMTP_ITERATOR {
        vstring_strcpy((iter)->dest, STR((iter)->saved_dest)); \
     } while (0)
 
+#define SMTP_ITER_UPDATE_HOST(iter, _host, _addr, _rr) do { \
+       vstring_strcpy((iter)->host, (_host)); \
+       vstring_strcpy((iter)->addr, (_addr)); \
+       (iter)->rr = (_rr); \
+       if ((_rr)->port) \
+           (iter)->port = htons((_rr)->port); /* SRV port override */ \
+    } while (0)
+
  /*
   * TLS Policy support.
   */
@@ -273,6 +281,7 @@ typedef struct SMTP_STATE {
 #define SMTP_MISC_FLAG_COMPLETE_SESSION        (1<<7)
 #define SMTP_MISC_FLAG_PREF_IPV6       (1<<8)
 #define SMTP_MISC_FLAG_PREF_IPV4       (1<<9)
+#define SMTP_MISC_FLAG_FALLBACK_SRV_TO_MX (1<<10)
 
 #define SMTP_MISC_FLAG_CONN_CACHE_MASK \
        (SMTP_MISC_FLAG_CONN_LOAD | SMTP_MISC_FLAG_CONN_STORE)
@@ -312,6 +321,8 @@ extern MAPS *smtp_generic_maps;             /* make internal address valid */
 extern int smtp_ext_prop_mask;         /* address extension propagation */
 extern unsigned smtp_dns_res_opt;      /* DNS query flags */
 
+extern STRING_LIST *smtp_use_srv_lookup;/* services with SRV record lookup */
+
 #ifdef USE_TLS
 
 extern TLS_APPL_STATE *smtp_tls_ctx;   /* client-side TLS engine */
index 2b5c126e5ad18767b504c95c44fa696264d7a925..a31cb38c1c04cde2e000b85180ac5a6e3cd64a4e 100644 (file)
 /*     char    *name;
 /*     int     misc_flags;
 /*     DSN_BUF *why;
+/*
+/*     DNS_RR  *smtp_service_addr(name, service, mxrr, misc_flags, why,
+/*                                     found_myself)
+/*     const char *name;
+/*     const char *service;
+/*     DNS_RR  **mxrr;
+/*     int     misc_flags;
+/*     DSN_BUF *why;
+/*     int     *found_myself;
 /* DESCRIPTION
 /*     This module implements Internet address lookups. By default,
 /*     lookups are done via the Internet domain name service (DNS).
@@ -33,6 +42,8 @@
 /*     destination.  If MX records were found, the rname, qname,
 /*     and dnssec validation status of the MX RRset are returned
 /*     via mxrr, which the caller must free with dns_rr_free().
+/*     Fallback from MX to address lookups is governed by RFC 2821,
+/*     and by local policy (var_ign_mx_lookup_err).
 /*
 /*     When no mail exchanger is listed in the DNS for \fIname\fR, the
 /*     request is passed to smtp_host_addr().
 /*     host.  The host can be specified as a numerical Internet network
 /*     address, or as a symbolic host name.
 /*
-/*     Results from smtp_domain_addr() or smtp_host_addr() are
-/*     destroyed by dns_rr_free(), including null lists.
+/*     smtp_service_addr() looks up addresses for hosts specified
+/*     in SRV records for the specified domain and service. This
+/*     supports the features of smtp_domain_addr() except that
+/*     the order of SRV records is determined by RFC 2782, and
+/*     that address records are not sorted by IP address family
+/*     preference.  Fallback from SRV to MX or address lookups is
+/*     governed by local policy (var_ign_mx_lookup_err and
+/*     var_allow_srv_fallback).
+/*
+/*     Results from smtp_domain_addr(), smtp_host_addr(), and
+/*     smtp_service_addr() are destroyed by dns_rr_free(), including
+/*     null lists.
 /* DIAGNOSTICS
 /*     Panics: interface violations. For example, calling smtp_domain_addr()
 /*     when DNS lookups are explicitly disabled.
 /*     Google, Inc.
 /*     111 8th Avenue
 /*     New York, NY 10011, USA
+/*
+/*     SRV Support by
+/*     Tomas Korbar
+/*     Red Hat, Inc.
 /*--*/
 
 /* System library. */
@@ -130,7 +155,8 @@ static void smtp_print_addr(const char *what, DNS_RR *addr_list)
 /* smtp_addr_one - address lookup for one host name */
 
 static DNS_RR *smtp_addr_one(DNS_RR *addr_list, const char *host, int res_opt,
-                                    unsigned pref, DSN_BUF *why)
+                                    unsigned pref, unsigned port,
+                                    DSN_BUF *why)
 {
     const char *myname = "smtp_addr_one";
     DNS_RR *addr = 0;
@@ -154,6 +180,8 @@ static DNS_RR *smtp_addr_one(DNS_RR *addr_list, const char *host, int res_opt,
                msg_fatal("host %s: conversion error for address family "
                          "%d: %m", host, res0->ai_addr->sa_family);
            addr_list = dns_rr_append(addr_list, addr);
+           addr->pref = pref;
+           addr->port = port;
            if (msg_verbose)
                msg_info("%s: using numerical host %s", myname, host);
            freeaddrinfo(res0);
@@ -174,8 +202,10 @@ static DNS_RR *smtp_addr_one(DNS_RR *addr_list, const char *host, int res_opt,
                             why->reason, DNS_REQ_FLAG_NONE,
                             proto_info->dns_atype_list)) {
        case DNS_OK:
-           for (rr = addr; rr; rr = rr->next)
+           for (rr = addr; rr; rr = rr->next) {
                rr->pref = pref;
+               rr->port = port;
+           }
            addr_list = dns_rr_append(addr_list, addr);
            return (addr_list);
        default:
@@ -293,10 +323,10 @@ static DNS_RR *smtp_addr_list(DNS_RR *mx_names, DSN_BUF *why)
      * tweaking the in-process resolver flags.
      */
     for (rr = mx_names; rr; rr = rr->next) {
-       if (rr->type != T_MX)
+       if (rr->type != T_MX && rr->type != T_SRV)
            msg_panic("smtp_addr_list: bad resource type: %d", rr->type);
        addr_list = smtp_addr_one(addr_list, (char *) rr->data, res_opt,
-                                 rr->pref, why);
+                                 rr->pref, rr->port, why);
     }
     return (addr_list);
 }
@@ -678,7 +708,7 @@ DNS_RR *smtp_host_addr(const char *host, int misc_flags, DSN_BUF *why)
      * address to internal form. Otherwise, the host is specified by name.
      */
 #define PREF0  0
-    addr_list = smtp_addr_one((DNS_RR *) 0, ahost, res_opt, PREF0, why);
+    addr_list = smtp_addr_one((DNS_RR *) 0, ahost, res_opt, PREF0, 0, why);
     if (addr_list
        && (misc_flags & SMTP_MISC_FLAG_LOOP_DETECT)
        && smtp_find_self(addr_list) != 0) {
@@ -700,3 +730,129 @@ DNS_RR *smtp_host_addr(const char *host, int misc_flags, DSN_BUF *why)
        smtp_print_addr(host, addr_list);
     return (addr_list);
 }
+
+/* smtp_service_addr - service address lookup */
+
+DNS_RR *smtp_service_addr(const char *name, const char *service, DNS_RR **mxrr,
+                                 int misc_flags, DSN_BUF *why,
+                                 int *found_myself)
+{
+    static VSTRING *srv_qname = 0;
+    const char *str_srv_qname;
+    DNS_RR *srv_names = 0;
+    DNS_RR *addr_list = 0;
+    DNS_RR *self = 0;
+    unsigned best_pref;
+    unsigned best_found;
+    int     r = 0;
+    const char *aname;
+    int     allow_non_srv_fallback = var_allow_srv_fallback;
+
+    dsb_reset(why);
+
+    /*
+     * Sanity check.
+     */
+    if (smtp_dns_support == SMTP_DNS_DISABLED)
+       msg_panic("smtp_service_addr: DNS lookup is disabled");
+
+    if (smtp_dns_support == SMTP_DNS_DNSSEC) {
+       r |= RES_USE_DNSSEC;
+    }
+    if (srv_qname == 0)
+       srv_qname = vstring_alloc(100);
+    vstring_sprintf(srv_qname, "_%s._tcp.%s", service, name);
+    str_srv_qname = STR(srv_qname);
+
+    /*
+     * IDNA support.
+     */
+#ifndef NO_EAI
+    if (!allascii(str_srv_qname)
+       && (aname = midna_domain_to_ascii(str_srv_qname)) != 0) {
+       if (msg_verbose)
+           msg_info("%s asciified to %s", str_srv_qname, aname);
+    } else
+#endif
+       aname = str_srv_qname;
+
+    switch (dns_lookup(aname, T_SRV, r, &srv_names, (VSTRING *) 0,
+                      why->reason)) {
+    default:
+       dsb_status(why, "4.4.3");
+       allow_non_srv_fallback |= var_ign_srv_lookup_err;
+       break;
+    case DNS_INVAL:
+       dsb_status(why, "5.4.4");
+       allow_non_srv_fallback |= var_ign_srv_lookup_err;
+       break;
+    case DNS_POLICY:
+       dsb_status(why, "4.7.0");
+       break;
+    case DNS_FAIL:
+       dsb_status(why, "5.4.3");
+       allow_non_srv_fallback |= var_ign_srv_lookup_err;
+       break;
+    case DNS_NULLSRV:
+       dsb_status(why, "5.1.0");
+       break;
+    case DNS_OK:
+       /* Shuffle then sort the SRV rr records by priority and weight. */
+       srv_names = dns_srv_rr_sort(srv_names);
+       best_pref = (srv_names ? srv_names->pref : IMPOSSIBLE_PREFERENCE);
+       addr_list = smtp_addr_list(srv_names, why);
+       if (mxrr)
+           *mxrr = dns_rr_copy(srv_names);     /* copies one record! */
+       dns_rr_free(srv_names);
+       if (addr_list == 0) {
+           msg_warn("no SRV host for %s has a valid address record",
+                    str_srv_qname);
+           break;
+       }
+       /* Optional loop prevention, similar to smtp_domain_addr(). */
+       best_found = (addr_list ? addr_list->pref : IMPOSSIBLE_PREFERENCE);
+       if (msg_verbose)
+           smtp_print_addr(aname, addr_list);
+       if ((misc_flags & SMTP_MISC_FLAG_LOOP_DETECT)
+           && (self = smtp_find_self(addr_list)) != 0) {
+           addr_list = smtp_truncate_self(addr_list, self->pref);
+           if (addr_list == 0) {
+               if (best_pref != best_found) {
+                   dsb_simple(why, "4.4.4",
+                              "unable to find primary relay for %s",
+                              str_srv_qname);
+               } else {
+                   dsb_simple(why, "5.4.6", "mail for %s loops back to myself",
+                              str_srv_qname);
+               }
+           }
+       }
+       /* TODO: sort by priority, weight, and address family preference. */
+
+       /* Optional address family balancing, as in smtp_domain_addr(). */
+       if (addr_list && addr_list->next) {
+           if (var_smtp_mxaddr_limit > 0 && var_smtp_balance_inet_proto)
+               addr_list = smtp_balance_inet_proto(addr_list, misc_flags,
+                                                   var_smtp_mxaddr_limit);
+       }
+       break;
+    case DNS_NOTFOUND:
+       dsb_status(why, "5.4.4");
+       break;
+    }
+    *found_myself |= (self != 0);
+
+    /*
+     * If permitted, fall back to non-SRV record lookups.
+     */
+    if (addr_list == 0 && allow_non_srv_fallback) {
+       msg_info("skipping SRV lookup for %s: %s",
+                str_srv_qname, STR(why->reason));
+       if (misc_flags & SMTP_MISC_FLAG_FALLBACK_SRV_TO_MX)
+           addr_list = smtp_domain_addr(name, mxrr, misc_flags, why,
+                                        found_myself);
+       else
+           addr_list = smtp_host_addr(name, misc_flags, why);
+    }
+    return (addr_list);
+}
index 8f20961e560a96e6d7821b30fd77d8a01678068c..60ea2b47eabca0fee20615351ea4a025d49e75e8 100644 (file)
@@ -18,6 +18,7 @@
   */
 extern DNS_RR *smtp_host_addr(const char *, int, DSN_BUF *);
 extern DNS_RR *smtp_domain_addr(const char *, DNS_RR **, int, DSN_BUF *, int *);
+extern DNS_RR *smtp_service_addr(const char *, const char *, DNS_RR **, int, DSN_BUF *, int *);
 
 /* LICENSE
 /* .ad
@@ -28,4 +29,9 @@ extern DNS_RR *smtp_domain_addr(const char *, DNS_RR **, int, DSN_BUF *, int *);
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
 /*--*/
index ed58180f6280169967074f7953e35b9a4883b092..68faca18ef821ab73c6434d2c2039f64ab0e7e62 100644 (file)
@@ -28,7 +28,8 @@
 /*     destinations may be specified as "unix:pathname", "inet:host"
 /*     or "inet:host:port".
 /*
-/*     With SMTP, the Internet domain name service is queried for mail
+/*     With SMTP, or with SRV record lookup enabled, the Internet
+/*     domain name service is queried for mail
 /*     exchanger hosts. Quote the domain name with `[' and `]' to
 /*     suppress mail exchanger lookups.
 /*
@@ -357,7 +358,8 @@ static SMTP_SESSION *smtp_connect_sock(int sock, struct sockaddr *sa,
 /* smtp_parse_destination - parse host/port destination */
 
 static char *smtp_parse_destination(char *destination, char *def_service,
-                                           char **hostp, unsigned *portp)
+                                           char **hostp, char **servicep,
+                                           unsigned *portp)
 {
     char   *buf = mystrdup(destination);
     char   *service;
@@ -373,13 +375,13 @@ static char *smtp_parse_destination(char *destination, char *def_service,
      * Parse the host/port information. We're working with a copy of the
      * destination argument so the parsing can be destructive.
      */
-    if ((err = host_port(buf, hostp, (char *) 0, &service, def_service)) != 0)
+    if ((err = host_port(buf, hostp, (char *) 0, servicep, def_service)) != 0)
        msg_fatal("%s in server description: %s", err, destination);
 
     /*
      * Convert service to port number, network byte order.
      */
-    service = (char *) filter_known_tcp_port(service);
+    service = (char *) filter_known_tcp_port(*servicep);
     if (alldig(service)) {
        if ((port = atoi(service)) >= 65536 || port == 0)
            msg_fatal("bad network port: %s for destination: %s",
@@ -661,6 +663,9 @@ static void smtp_update_addr_list(DNS_RR **addr_list, const char *server_addr,
      * XXX Extend the SMTP_SESSION structure with sockaddr information so that
      * we can avoid repeated string->binary transformations for the same
      * address.
+     * 
+     * XXX SRV support: this should match the port, too, otherwise we may
+     * eliminate too many list entries.
      */
     if ((aierr = hostaddr_to_sockaddr(server_addr, (char *) 0, 0, &res0)) != 0) {
        msg_warn("hostaddr_to_sockaddr %s: %s",
@@ -691,6 +696,18 @@ static int smtp_reuse_session(SMTP_STATE *state, DNS_RR **addr_list,
     DSN_BUF *why = state->why;
 
     /*
+     * This code is called after server address/port lookup, before
+     * iter->host, iter->addr, iter->rr and iter->mx are assigned concrete
+     * values, and while iter->port still corresponds to the nexthop service,
+     * or the default service configured with smtp_tcp_port or lmtp_tcp_port.
+     * 
+     * When a connection is reused by nexthop/service or by server address/port,
+     * iter->host, iter->addr and iter->port are updated with actual values
+     * from the cached session. Additionally, when a connection is searched
+     * by nexthop/service, iter->rr remains null, and when a connection is
+     * searched by server address/port, iter->rr is updated with an actual
+     * server address/port before the search is made.
+     * 
      * First, search the cache by delivery request nexthop. We truncate the
      * server address list when all the sessions for this destination are
      * used up, to reduce the number of variables that need to be checked
@@ -757,9 +774,7 @@ static int smtp_reuse_session(SMTP_STATE *state, DNS_RR **addr_list,
            /* XXX Assume there is no code at the end of this loop. */
            continue;
        }
-       vstring_strcpy(iter->addr, hostaddr.buf);
-       vstring_strcpy(iter->host, SMTP_HNAME(addr));
-       iter->rr = addr;
+       SMTP_ITER_UPDATE_HOST(iter, SMTP_HNAME(addr), hostaddr.buf, addr);
 #ifdef USE_TLS
        if (!smtp_tls_policy_cache_query(why, state->tls, iter)) {
            msg_warn("TLS policy lookup error for %s/%s: %s",
@@ -844,6 +859,7 @@ static void smtp_connect_inet(SMTP_STATE *state, const char *nexthop,
        char   *dest_buf;
        char   *domain;
        unsigned port;
+       char   *service;
        DNS_RR *addr_list;
        DNS_RR *addr;
        DNS_RR *next;
@@ -851,6 +867,8 @@ static void smtp_connect_inet(SMTP_STATE *state, const char *nexthop,
        int     sess_count;
        SMTP_SESSION *session;
        int     lookup_mx;
+       int     non_dns_or_literal;
+       int     i_am_mx;
        unsigned domain_best_pref;
        MAI_HOSTADDR_STR hostaddr;
 
@@ -860,8 +878,28 @@ static void smtp_connect_inet(SMTP_STATE *state, const char *nexthop,
        /*
         * Parse the destination. If no TCP port is specified, use the port
         * that is reserved for the protocol (SMTP or LMTP).
+        * 
+        * The 'service' variable corresponds to the remote service specified
+        * with the nexthop, or the default service configured with
+        * smtp_tcp_port or lmtp_tcp_port. The 'port' variable and
+        * SMTP_ITERATOR.port initially correspond to that service. This
+        * determines what loop prevention will be in effect.
+        * 
+        * The SMTP_ITERATOR.port will be overwritten after SRV record lookup.
+        * This guarantees that the connection cache key contains the correct
+        * port value when caching and retrieving a connection by its server
+        * address (and port).
+        * 
+        * By design, the connection cache key contains NO port information when
+        * caching or retrieving a connection by its nexthop destination.
+        * Instead, the cache key contains the master.cf service name (a
+        * proxy for all the parameter settings including the default service
+        * from smtp_tcp_port or lmtp_tcp_port), together with the nexthop
+        * destination and sender-dependent info. This should be sufficient
+        * to avoid cross talk between mail streams that should be separated.
         */
-       dest_buf = smtp_parse_destination(dest, def_service, &domain, &port);
+       dest_buf = smtp_parse_destination(dest, def_service, &domain,
+                                         &service, &port);
        if (var_helpful_warnings && var_smtp_tls_wrappermode == 0
            && ntohs(port) == 465) {
            msg_info("SMTPS wrappermode (TCP port 465) requires setting "
@@ -874,32 +912,48 @@ static void smtp_connect_inet(SMTP_STATE *state, const char *nexthop,
        SMTP_ITER_INIT(iter, dest, NO_HOST, NO_ADDR, port, state);
 
        /*
-        * Resolve an SMTP or LMTP server. In the case of SMTP, skip mail
-        * exchanger lookups when a quoted host is specified or when DNS
-        * lookups are disabled.
+        * Resolve an SMTP or LMTP server. Skip MX or SRV lookups when a
+        * quoted domain is specified or when DNS lookups are disabled.
         */
        if (msg_verbose)
-           msg_info("connecting to %s port %d", domain, ntohs(port));
+           msg_info("connecting to %s service %s", domain, service);
+       non_dns_or_literal = (smtp_dns_support == SMTP_DNS_DISABLED
+                             || *dest == '[');
        if (smtp_mode) {
            if (ntohs(port) == IPPORT_SMTP)
                state->misc_flags |= SMTP_MISC_FLAG_LOOP_DETECT;
            else
                state->misc_flags &= ~SMTP_MISC_FLAG_LOOP_DETECT;
-           lookup_mx = (smtp_dns_support != SMTP_DNS_DISABLED && *dest != '[');
+           lookup_mx = !non_dns_or_literal;
        } else
            lookup_mx = 0;
-       if (!lookup_mx) {
+
+       /*
+        * Look up SRV and address records and fall back to non-SRV lookups
+        * if permitted by configuration settings, or look up MX and address
+        * records, or look up address records only.
+        */
+       i_am_mx = 0;
+       addr_list = 0;
+       if (!non_dns_or_literal && smtp_use_srv_lookup
+           && string_list_match(smtp_use_srv_lookup, service)) {
+           if (lookup_mx)
+               state->misc_flags |= SMTP_MISC_FLAG_FALLBACK_SRV_TO_MX;
+           else
+               state->misc_flags &= ~SMTP_MISC_FLAG_FALLBACK_SRV_TO_MX;
+           addr_list = smtp_service_addr(domain, service, &iter->mx,
+                                         state->misc_flags, why, &i_am_mx);
+       } else if (!lookup_mx) {
+           /* Non-DNS, literal, or non-SMTP service */
            addr_list = smtp_host_addr(domain, state->misc_flags, why);
            /* XXX We could be an MX host for this destination... */
        } else {
-           int     i_am_mx = 0;
-
            addr_list = smtp_domain_addr(domain, &iter->mx, state->misc_flags,
                                         why, &i_am_mx);
-           /* If we're MX host, don't connect to non-MX backups. */
-           if (i_am_mx)
-               state->misc_flags |= SMTP_MISC_FLAG_FINAL_NEXTHOP;
        }
+       /* If we're MX host, don't connect to non-MX backups. */
+       if (i_am_mx)
+           state->misc_flags |= SMTP_MISC_FLAG_FINAL_NEXTHOP;
 
        /*
         * Don't try fall-back hosts if mail loops to myself. That would just
@@ -992,9 +1046,7 @@ static void smtp_connect_inet(SMTP_STATE *state, const char *nexthop,
                /* XXX Assume there is no code at the end of this loop. */
                continue;
            }
-           vstring_strcpy(iter->addr, hostaddr.buf);
-           vstring_strcpy(iter->host, SMTP_HNAME(addr));
-           iter->rr = addr;
+           SMTP_ITER_UPDATE_HOST(iter, SMTP_HNAME(addr), hostaddr.buf, addr);
 #ifdef USE_TLS
            if (!smtp_tls_policy_cache_query(why, state->tls, iter)) {
                msg_warn("TLS policy lookup for %s/%s: %s",
index cd54f8fcbdfe8b199ddb2a881a1e963f5002e36d..22f4709c18bea5a85eaf733824536b90d658e286 100644 (file)
@@ -66,6 +66,7 @@
        VAR_SMTP_DNS_RE_FILTER, DEF_SMTP_DNS_RE_FILTER, &var_smtp_dns_re_filter, 0, 0,
        VAR_TLSPROXY_SERVICE, DEF_TLSPROXY_SERVICE, &var_tlsproxy_service, 1, 0,
        VAR_HFROM_FORMAT, DEF_HFROM_FORMAT, &var_hfrom_format, 1, 0,
+       VAR_USE_SRV_LOOKUP, DEF_USE_SRV_LOOKUP, &var_use_srv_lookup, 0, 0,
        0,
     };
     static const CONFIG_TIME_TABLE smtp_time_table[] = {
        VAR_SMTP_DUMMY_MAIL_AUTH, DEF_SMTP_DUMMY_MAIL_AUTH, &var_smtp_dummy_mail_auth,
        VAR_SMTP_BALANCE_INET_PROTO, DEF_SMTP_BALANCE_INET_PROTO, &var_smtp_balance_inet_proto,
        VAR_SMTP_BIND_ADDR_ENFORCE, DEF_SMTP_BIND_ADDR_ENFORCE, &var_smtp_bind_addr_enforce,
+       VAR_IGN_SRV_LOOKUP_ERR, DEF_IGN_SRV_LOOKUP_ERR, &var_ign_srv_lookup_err,
+       VAR_ALLOW_SRV_FALLBACK, DEF_ALLOW_SRV_FALLBACK, &var_allow_srv_fallback,
        0,
     };
     static const CONFIG_NBOOL_TABLE smtp_nbool_table[] = {
index f93ba296a0fe5b43170d2c33234b466cd5706539..288483f7673c55ae9db3afb57b43bca5962ed971 100644 (file)
@@ -172,6 +172,11 @@ static SMTP_SESSION *smtp_reuse_common(SMTP_STATE *state, int fd,
     SMTP_ITERATOR *iter = state->iterator;
     SMTP_SESSION *session;
 
+    if (msg_verbose) {
+       msg_info("%s: dest_prop='%s'", myname, STR(state->dest_prop));
+       msg_info("%s: endp_prop='%s'", myname, STR(state->endp_prop));
+    }
+
     /*
      * Re-activate the SMTP_SESSION object.
      */
@@ -211,6 +216,7 @@ static SMTP_SESSION *smtp_reuse_common(SMTP_STATE *state, int fd,
 
 SMTP_SESSION *smtp_reuse_nexthop(SMTP_STATE *state, int name_key_flags)
 {
+    const char *myname = "smtp_reuse_nexthop";
     SMTP_SESSION *session;
     int     fd;
 
@@ -219,6 +225,8 @@ SMTP_SESSION *smtp_reuse_nexthop(SMTP_STATE *state, int name_key_flags)
      */
     smtp_key_prefix(state->dest_label, SMTP_REUSE_KEY_DELIM_NA,
                    state->iterator, name_key_flags);
+    if (msg_verbose)
+       msg_info("%s: dest_label='%s'", myname, STR(state->dest_label));
     if ((fd = scache_find_dest(smtp_scache, STR(state->dest_label),
                               state->dest_prop, state->endp_prop)) < 0)
        return (0);
@@ -235,6 +243,7 @@ SMTP_SESSION *smtp_reuse_nexthop(SMTP_STATE *state, int name_key_flags)
 
 SMTP_SESSION *smtp_reuse_addr(SMTP_STATE *state, int endp_key_flags)
 {
+    const char *myname = "smtp_reuse_addr";
     SMTP_SESSION *session;
     int     fd;
 
@@ -253,6 +262,8 @@ SMTP_SESSION *smtp_reuse_addr(SMTP_STATE *state, int endp_key_flags)
      */
     smtp_key_prefix(state->endp_label, SMTP_REUSE_KEY_DELIM_NA,
                    state->iterator, endp_key_flags);
+    if (msg_verbose)
+       msg_info("%s: endp_label='%s'", myname, STR(state->endp_label));
     if ((fd = scache_find_endp(smtp_scache, STR(state->endp_label),
                               state->endp_prop)) < 0)
        return (0);
index 9f139784300f9338c3939a816ed7ad48e425c760..90a0ff1e136ea0e8a74c8885e7ca191e7c19268a 100644 (file)
 #define SESS_ATTR_DEST         "destination"
 #define SESS_ATTR_HOST         "host_name"
 #define SESS_ATTR_ADDR         "host_addr"
+#define SESS_ATTR_PORT         "host_port"
 #define SESS_ATTR_DEST_FEATURES        "destination_features"
 
 #define SESS_ATTR_TLS_LEVEL    "tls_level"
@@ -259,6 +260,7 @@ int     smtp_session_passivate(SMTP_SESSION *session, VSTRING *dest_prop,
                            SEND_ATTR_STR(SESS_ATTR_DEST, STR(iter->dest)),
                            SEND_ATTR_STR(SESS_ATTR_HOST, STR(iter->host)),
                            SEND_ATTR_STR(SESS_ATTR_ADDR, STR(iter->addr)),
+                           SEND_ATTR_UINT(SESS_ATTR_PORT, iter->port),
                            SEND_ATTR_INT(SESS_ATTR_DEST_FEATURES,
                         session->features & SMTP_FEATURE_DESTINATION_MASK),
                            ATTR_TYPE_END) != 0
@@ -398,9 +400,10 @@ SMTP_SESSION *smtp_session_activate(int fd, SMTP_ITERATOR *iter,
                               RECV_ATTR_STR(SESS_ATTR_DEST, iter->dest),
                               RECV_ATTR_STR(SESS_ATTR_HOST, iter->host),
                               RECV_ATTR_STR(SESS_ATTR_ADDR, iter->addr),
+                              RECV_ATTR_UINT(SESS_ATTR_PORT, &iter->port),
                               RECV_ATTR_INT(SESS_ATTR_DEST_FEATURES,
                                             &dest_features),
-                              ATTR_TYPE_END) != 4
+                              ATTR_TYPE_END) != 5
            || vstream_fclose(mp) != 0) {
            msg_warn("smtp_session_passivate: bad cached dest properties");
            SMTP_SESSION_ACTIVATE_ERR_RETURN();
index b8d2c52e6ecadfa9ca4fee9f63d52cdb01086419..143d44171aa2bdd4db712c8cb0f11af9c3ce4260 100644 (file)
 /* .IP "\fBsmtpd_dns_reply_filter (empty)\fR"
 /*     Optional filter for Postfix SMTP server DNS lookup results.
 /* .PP
+/*     Available in Postfix 3.5 and later:
+/* .IP "\fBinfo_log_address_format (external)\fR"
+/*     The email address form that will be used in non-debug logging
+/*     (info, warning, etc.).
+/* .PP
 /*     Available in Postfix version 3.6 and later:
 /* .IP "\fBsmtpd_relay_before_recipient_restrictions (see 'postconf -d' output)\fR"
 /*     Evaluate smtpd_relay_restrictions before smtpd_recipient_restrictions.
 /*     A workaround for implementations that hang Postfix while shutting
 /*     down a TLS session, until Postfix times out.
 /* .PP
-/*     Available in Postfix 3.5 and later:
-/* .IP "\fBinfo_log_address_format (external)\fR"
-/*     The email address form that will be used in non-debug logging
-/*     (info, warning, etc.).
-/* .PP
 /*     Available in Postfix version 3.8 and later:
 /* .IP "\fBtls_ffdhe_auto_groups (see 'postconf -d' output)\fR"
 /*     The prioritized list of finite-field Diffie-Hellman ephemeral
index 29e8671a41c593b18dbb3970a550e4250fd78a9b..b6a2aced680235f58384ce223dbb1560474665b5 100644 (file)
@@ -3065,8 +3065,8 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
        || type == T_AAAA
 #endif
        ) {
-       server_list = dns_rr_create(domain, domain, T_MX, C_IN, 0, 0,
-                                   domain, strlen(domain) + 1);
+       server_list = dns_rr_create_nopref(domain, domain, T_MX, C_IN, 0,
+                                          domain, strlen(domain) + 1);
     } else {
        dns_status = dns_lookup(domain, type, 0, &server_list,
                                (VSTRING *) 0, (VSTRING *) 0);
@@ -3074,8 +3074,8 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
            return (SMTPD_CHECK_DUNNO);
        if (dns_status == DNS_NOTFOUND /* Not: h_errno == NO_DATA */ ) {
            if (type == T_MX) {
-               server_list = dns_rr_create(domain, domain, type, C_IN, 0, 0,
-                                           domain, strlen(domain) + 1);
+               server_list = dns_rr_create_nopref(domain, domain, type, C_IN,
+                                            0, domain, strlen(domain) + 1);
                dns_status = DNS_OK;
            } else if (type == T_NS /* && h_errno == NO_DATA */ ) {
                while ((domain = strchr(domain, '.')) != 0 && domain[1]) {
index 067405f58f206a885f6675bb4d1d490c9f510ce5..7cd0cf2851f4211a5ad1d4b22b14244bf9051580 100644 (file)
@@ -62,6 +62,7 @@ typedef int (*ATTR_PRINT_CUSTOM_FN) (ATTR_PRINT_COMMON_FN, VSTREAM *, int, const
   * for documentation.
   */
 #define SEND_ATTR_INT(name, val)       ATTR_TYPE_INT, CHECK_CPTR(ATTR, char, (name)), CHECK_VAL(ATTR, int, (val))
+#define SEND_ATTR_UINT(name, val)      ATTR_TYPE_INT, CHECK_CPTR(ATTR, char, (name)), CHECK_VAL(ATTR, unsigned, (val))
 #define SEND_ATTR_STR(name, val)       ATTR_TYPE_STR, CHECK_CPTR(ATTR, char, (name)), CHECK_CPTR(ATTR, char, (val))
 #define SEND_ATTR_HASH(val)            ATTR_TYPE_HASH, CHECK_CPTR(ATTR, HTABLE, (val))
 #define SEND_ATTR_NV(val)              ATTR_TYPE_NV, CHECK_CPTR(ATTR, NVTABLE, (val))
@@ -70,6 +71,7 @@ typedef int (*ATTR_PRINT_CUSTOM_FN) (ATTR_PRINT_COMMON_FN, VSTREAM *, int, const
 #define SEND_ATTR_FUNC(func, val)      ATTR_TYPE_FUNC, CHECK_VAL(ATTR, ATTR_PRINT_CUSTOM_FN, (func)), CHECK_CPTR(ATTR, void, (val))
 
 #define RECV_ATTR_INT(name, val)       ATTR_TYPE_INT, CHECK_CPTR(ATTR, char, (name)), CHECK_PTR(ATTR, int, (val))
+#define RECV_ATTR_UINT(name, val)      ATTR_TYPE_INT, CHECK_CPTR(ATTR, char, (name)), CHECK_PTR(ATTR, unsigned, (val))
 #define RECV_ATTR_STR(name, val)       ATTR_TYPE_STR, CHECK_CPTR(ATTR, char, (name)), CHECK_PTR(ATTR, VSTRING, (val))
 #define RECV_ATTR_STREQ(name, val)     ATTR_TYPE_STREQ, CHECK_CPTR(ATTR, char, (name)), CHECK_CPTR(ATTR, char, (val))
 #define RECV_ATTR_HASH(val)            ATTR_TYPE_HASH, CHECK_PTR(ATTR, HTABLE, (val))
@@ -81,9 +83,11 @@ typedef int (*ATTR_PRINT_CUSTOM_FN) (ATTR_PRINT_COMMON_FN, VSTREAM *, int, const
 CHECK_VAL_HELPER_DCL(ATTR, ssize_t);
 CHECK_VAL_HELPER_DCL(ATTR, long);
 CHECK_VAL_HELPER_DCL(ATTR, int);
+CHECK_VAL_HELPER_DCL(ATTR, unsigned);
 CHECK_PTR_HELPER_DCL(ATTR, void);
 CHECK_PTR_HELPER_DCL(ATTR, long);
 CHECK_PTR_HELPER_DCL(ATTR, int);
+CHECK_PTR_HELPER_DCL(ATTR, unsigned);
 CHECK_PTR_HELPER_DCL(ATTR, VSTRING);
 CHECK_PTR_HELPER_DCL(ATTR, NVTABLE);
 CHECK_PTR_HELPER_DCL(ATTR, HTABLE);
index 37e460f9ccf363b3c38c276de07481d8785a442e..924718531d75516ea2ce31657b85bce13de5efe0 100644 (file)
@@ -748,6 +748,17 @@ extern int initgroups(const char *, int);
 #define PIPES_CANT_FIONREAD
 #endif
 
+ /*
+  * GLIBC, mainly, but not exclusively Linux
+  */
+#ifdef __GLIBC_PREREQ
+#define HAVE_GLIBC_API_VERSION_SUPPORT(maj, min) __GLIBC_PREREQ(maj, min)
+#else
+#define HAVE_GLIBC_API_VERSION_SUPPORT(maj, min) \
+    (defined(__GLIBC__) && \
+       ((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min)))
+#endif
+
  /*
   * LINUX.
   */
@@ -782,13 +793,6 @@ extern int initgroups(const char *, int);
 #define NATIVE_NEWALIAS_PATH "/usr/bin/newaliases"
 #define NATIVE_COMMAND_DIR "/usr/sbin"
 #define NATIVE_DAEMON_DIR "/usr/libexec/postfix"
-#ifdef __GLIBC_PREREQ
-#define HAVE_GLIBC_API_VERSION_SUPPORT(maj, min) __GLIBC_PREREQ(maj, min)
-#else
-#define HAVE_GLIBC_API_VERSION_SUPPORT(maj, min) \
-    (defined(__GLIBC__) && \
-       ((__GLIBC__ << 16) + __GLIBC_MINOR__ >= ((maj) << 16) + (min)))
-#endif
 #if HAVE_GLIBC_API_VERSION_SUPPORT(2, 1)
 #define SOCKADDR_SIZE  socklen_t
 #define SOCKOPT_SIZE   socklen_t
index 1998a7c202099ff817be5ac188eaa81b2ce0771f..15cc4df603cda4da126dcd3f0ab886d3452a47b2 100644 (file)
 /*     IBM T.J. Watson Research
 /*     P.O. Box 704
 /*     Yorktown Heights, NY 10598, USA
+/*
+/*     Wietse Venema
+/*     Google, Inc.
+/*     111 8th Avenue
+/*     New York, NY 10011, USA
 /*--*/
 
 /* System library. */
@@ -75,6 +80,7 @@ int     unix_send_fd(int fd, int sendfd)
     struct cmsghdr *cmptr;
 
     memset((void *) &msg, 0, sizeof(msg));     /* Fix 200512 */
+    memset((void *) &control_un, 0, sizeof(control_un));       /* Fix 202302 */
     msg.msg_control = control_un.control;
     if (unix_pass_fd_fix & UNIX_PASS_FD_FIX_CMSG_LEN) {
        msg.msg_controllen = CMSG_LEN(sizeof(sendfd));  /* Fix 200506 */