From: Wietse Venema Date: Sun, 19 Feb 2023 05:00:00 +0000 (-0500) Subject: postfix-3.8-20230219 X-Git-Tag: v3.8.0-RC1~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2047994eeee1dbf0d8c0537ba00acb8986a8a370;p=thirdparty%2Fpostfix.git postfix-3.8-20230219 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index d1545c53a..5041f17cf 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -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. diff --git a/postfix/README_FILES/SASL_README b/postfix/README_FILES/SASL_README index 580a0131d..4ea62d9b3 100644 --- a/postfix/README_FILES/SASL_README +++ b/postfix/README_FILES/SASL_README @@ -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). NNoottee diff --git a/postfix/WISHLIST b/postfix/WISHLIST index bee364895..71b1685ca 100644 --- a/postfix/WISHLIST +++ b/postfix/WISHLIST @@ -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? diff --git a/postfix/html/SASL_README.html b/postfix/html/SASL_README.html index f31391668..1ddd24bb2 100644 --- a/postfix/html/SASL_README.html +++ b/postfix/html/SASL_README.html @@ -267,7 +267,7 @@ in /usr/lib/sasl2/.

  • 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 +

  • 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 diff --git a/postfix/html/lmtp.8.html b/postfix/html/lmtp.8.html index bcdb904b9..696d3bf4c 100644 --- a/postfix/html/lmtp.8.html +++ b/postfix/html/lmtp.8.html @@ -152,6 +152,7 @@ SMTP(8) SMTP(8) 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) @@ -395,6 +396,21 @@ SMTP(8) SMTP(8) header_from_format (standard) The format of the Postfix-generated From: header. + Available in Postfix version 3.8 and later: + + use_srv_lookup (empty) + Enables discovery for the specified service(s) using DNS SRV + records. + + ignore_srv_lookup_error (no) + When SRV record lookup fails, fall back to MX or IP address + lookup as if SRV record lookups were not enabled. + + allow_srv_lookup_fallback (no) + 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 Available in Postfix version 2.0 and later: diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html index 95c8dca56..722bdc4ec 100644 --- a/postfix/html/postconf.5.html +++ b/postfix/html/postconf.5.html @@ -762,6 +762,17 @@ Example: + + +

    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.

    + +

    This feature is available in Postfix 3.8 and later.

    + +
    allow_untrusted_routing @@ -946,7 +957,7 @@ instead.

    -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.

    @@ -4017,6 +4028,17 @@ mis-delivery of mail.

    + + +
    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. + +

    This feature is available in Postfix 3.8 and later.

    + +
    import_environment @@ -21247,6 +21269,103 @@ only if it would otherwise be accepted.

    This feature is available in Postfix 2.6 and later.

    + + +
    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.

    + +

    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.

    + +

    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.

    + +

    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".

    + +
    +/etc/postfix/main.cf:
    +    use_srv_lookup = submission
    +    relayhost = example.com:submission
    +    smtp_tls_security_level = may
    +    ...see SASL_README for sasl configuration...
    +
    + +

    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". +

    + +

    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".

    + +
    +/etc/postfix/main.cf:
    +    use_srv_lookup = submissions
    +    default_transport = smtp-wraptls:example.org:submissions
    +    ...see SASL_README for sasl configuration...
    +
    + +
    +/etc/postfix/master.cf:
    +    smtp-wraptls   unix   ...   ...   ...   ...   ...   smtp
    +        -o { smtp_tls_wrappermode = yes }
    +        -o { smtp_tls_security_level = encrypt }
    +
    + +

    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".

    + +
    +/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...
    +
    + +

    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. +

    + +
    +/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
    +
    + +

    This feature is available in Postfix 3.8 and later.

    + +
    verp_delimiter_filter diff --git a/postfix/html/posttls-finger.1.html b/postfix/html/posttls-finger.1.html index 401ad0726..877a2fa67 100644 --- a/postfix/html/posttls-finger.1.html +++ b/postfix/html/posttls-finger.1.html @@ -271,6 +271,8 @@ POSTTLS-FINGER(1) POSTTLS-FINGER(1) the -m option. By default reconnection is disabled, specify a positive delay to enable this behavior. + -R Use SRV lookup instead of MX. + -s servername The server name to send with the TLS Server Name Indication (SNI) extension. When the server has DANE TLSA records, this diff --git a/postfix/html/smtp.8.html b/postfix/html/smtp.8.html index bcdb904b9..696d3bf4c 100644 --- a/postfix/html/smtp.8.html +++ b/postfix/html/smtp.8.html @@ -152,6 +152,7 @@ SMTP(8) SMTP(8) 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) @@ -395,6 +396,21 @@ SMTP(8) SMTP(8) header_from_format (standard) The format of the Postfix-generated From: header. + Available in Postfix version 3.8 and later: + + use_srv_lookup (empty) + Enables discovery for the specified service(s) using DNS SRV + records. + + ignore_srv_lookup_error (no) + When SRV record lookup fails, fall back to MX or IP address + lookup as if SRV record lookups were not enabled. + + allow_srv_lookup_fallback (no) + 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 Available in Postfix version 2.0 and later: diff --git a/postfix/html/smtpd.8.html b/postfix/html/smtpd.8.html index 965bf11ff..f60ee85d0 100644 --- a/postfix/html/smtpd.8.html +++ b/postfix/html/smtpd.8.html @@ -159,32 +159,38 @@ SMTPD(8) SMTPD(8) smtpd_dns_reply_filter (empty) Optional filter for Postfix SMTP server DNS lookup results. + Available in Postfix 3.5 and later: + + info_log_address_format (external) + The email address form that will be used in non-debug logging + (info, warning, etc.). + Available in Postfix version 3.6 and later: smtpd_relay_before_recipient_restrictions (see 'postconf -d' output) - Evaluate smtpd_relay_restrictions before smtpd_recipi- + Evaluate smtpd_relay_restrictions before smtpd_recipi- ent_restrictions. - known_tcp_ports (lmtp=24, smtp=25, smtps=submissions=465, submis- + known_tcp_ports (lmtp=24, smtp=25, smtps=submissions=465, submis- sion=587) - Optional setting that avoids lookups in the services(5) data- + Optional setting that avoids lookups in the services(5) data- base. Available in Postfix version 3.7 and later: smtpd_per_request_deadline (normal: no, overload: yes) Change the behavior of the smtpd_timeout and smtpd_start- - tls_timeout 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. + tls_timeout 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. smtpd_min_data_rate (500) - 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 smtpd_per_request_deadline. ADDRESS REWRITING CONTROLS - See the ADDRESS_REWRITING_README document for a detailed discussion of + See the ADDRESS_REWRITING_README document for a detailed discussion of Postfix address rewriting. receive_override_options (empty) @@ -194,34 +200,34 @@ SMTPD(8) SMTPD(8) Available in Postfix version 2.2 and later: local_header_rewrite_clients (permit_inet_interfaces) - Rewrite or add message headers in mail from these clients, - updating incomplete addresses with the domain name in $myorigin + Rewrite or add message headers in mail from these clients, + updating incomplete addresses with the domain name in $myorigin or $mydomain, and adding missing headers. BEFORE-SMTPD PROXY AGENT Available in Postfix version 2.10 and later: smtpd_upstream_proxy_protocol (empty) - 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. smtpd_upstream_proxy_timeout (5s) - The time limit for the proxy protocol specified with the + The time limit for the proxy protocol specified with the smtpd_upstream_proxy_protocol parameter. AFTER QUEUE EXTERNAL CONTENT INSPECTION CONTROLS - 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 FILTER_README document for details. content_filter (empty) - After the message is queued, send the entire message to the + After the message is queued, send the entire message to the specified transport:destination. BEFORE QUEUE EXTERNAL CONTENT INSPECTION CONTROLS - 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 SMTPD_PROXY_README 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. smtpd_proxy_ehlo ($myhostname) - How the Postfix SMTP server announces itself to the proxy fil- + How the Postfix SMTP server announces itself to the proxy fil- ter. smtpd_proxy_options (empty) - 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. smtpd_proxy_timeout (100s) - 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. BEFORE QUEUE MILTER CONTROLS 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 MIL- + 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 MIL- TER_README document. smtpd_milters (empty) - 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 smtpd(8) server. milter_protocol (6) - 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. milter_default_action (tempfail) - 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). milter_macro_daemon_name ($myhostname) - The {daemon_name} macro value for Milter (mail filter) applica- + The {daemon_name} macro value for Milter (mail filter) applica- tions. milter_macro_v ($mail_name $mail_version) @@ -274,60 +280,60 @@ SMTPD(8) SMTPD(8) tion, and for negotiating protocol options. milter_command_timeout (30s) - 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. milter_content_timeout (300s) - 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. milter_connect_macros (see 'postconf -d' output) - 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. milter_helo_macros (see 'postconf -d' output) - 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. milter_mail_macros (see 'postconf -d' output) - 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. milter_rcpt_macros (see 'postconf -d' output) - 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. milter_data_macros (see 'postconf -d' output) - 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. milter_unknown_command_macros (see 'postconf -d' output) - 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. milter_end_of_header_macros (see 'postconf -d' output) - 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. milter_end_of_data_macros (see 'postconf -d' output) - 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: milter_macro_defaults (empty) - Optional list of name=value pairs that specify default values - for arbitrary macros that Postfix may send to Milter applica- + Optional list of name=value pairs that specify default values + for arbitrary macros that Postfix may send to Milter applica- tions. Available in Postfix version 3.2 and later: smtpd_milter_maps (empty) - Lookup tables with Milter settings per remote SMTP client IP + Lookup tables with Milter settings per remote SMTP client IP address. GENERAL CONTENT INSPECTION CONTROLS - 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. EXTERNAL CONTENT INSPECTION CONTROLS - 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: smtpd_authorized_xforward_hosts (empty) - What remote SMTP clients are allowed to use the XFORWARD fea- + What remote SMTP clients are allowed to use the XFORWARD fea- ture. SASL AUTHENTICATION CONTROLS Postfix SASL support (RFC 4954) 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 SASL_README document for + clients to the Postfix SMTP server, and to authenticate the Postfix + SMTP client to a remote SMTP server. See the SASL_README document for details. broken_sasl_auth_clients (no) - Enable interoperability with remote SMTP clients that implement + Enable interoperability with remote SMTP clients that implement an obsolete version of the AUTH command (RFC 4954). smtpd_sasl_auth_enable (no) Enable SASL authentication in the Postfix SMTP server. smtpd_sasl_local_domain (empty) - The name of the Postfix SMTP server's local SASL authentication + The name of the Postfix SMTP server's local SASL authentication realm. smtpd_sasl_security_options (noanonymous) 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 smtpd_sasl_type. smtpd_sender_login_maps (empty) - 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: smtpd_sasl_exceptions_networks (empty) - 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: smtpd_sasl_application_name (smtpd) - 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) smtpd_sasl_path (smtpd) 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 smtpd_sasl_type. smtpd_sasl_type (cyrus) - 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: smtpd_sasl_service (smtp) - 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 smtpd_sasl_type and smtpd_sasl_path. Available in Postfix version 3.4 and later: @@ -420,20 +426,20 @@ SMTPD(8) SMTPD(8) Available in Postfix 3.6 and later: smtpd_sasl_mechanism_filter (!external, static:rest) - 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. STARTTLS SUPPORT CONTROLS - Detailed information about STARTTLS configuration may be found in the + Detailed information about STARTTLS configuration may be found in the TLS_README document. smtpd_tls_security_level (empty) - 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 smtpd_use_tls and smtpd_enforce_tls. smtpd_sasl_tls_security_options ($smtpd_sasl_security_options) - 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. smtpd_starttls_timeout (see 'postconf -d' output) @@ -441,25 +447,25 @@ SMTPD(8) SMTPD(8) during TLS startup and shutdown handshake procedures. smtpd_tls_CAfile (empty) - 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. smtpd_tls_CApath (empty) - 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. smtpd_tls_always_issue_session_ids (yes) - Force the Postfix SMTP server to issue a TLS session id, even - when TLS session caching is turned off (smtpd_tls_ses- + Force the Postfix SMTP server to issue a TLS session id, even + when TLS session caching is turned off (smtpd_tls_ses- sion_cache_database is empty). smtpd_tls_ask_ccert (no) Ask a remote SMTP client for a client certificate. smtpd_tls_auth_only (no) - 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. smtpd_tls_exclude_ciphers (empty) - 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. smtpd_tls_dcert_file (empty) File with the Postfix SMTP server DSA certificate in PEM format. smtpd_tls_dh1024_param_file (empty) - 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. smtpd_tls_dh512_param_file (empty) - 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. smtpd_tls_dkey_file ($smtpd_tls_dcert_file) @@ -494,12 +500,12 @@ SMTPD(8) SMTPD(8) Enable additional Postfix SMTP server logging of TLS activity. smtpd_tls_mandatory_ciphers (medium) - 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. smtpd_tls_mandatory_exclude_ciphers (empty) - 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. smtpd_tls_mandatory_protocols (see 'postconf -d' output) @@ -508,21 +514,21 @@ SMTPD(8) SMTPD(8) smtpd_tls_received_header (no) 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. smtpd_tls_req_ccert (no) - 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. smtpd_tls_wrappermode (no) - 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. tls_daemon_random_bytes (32) - The number of pseudo-random bytes that an smtp(8) or smtpd(8) - process requests from the tlsmgr(8) server in order to seed its + The number of pseudo-random bytes that an smtp(8) or smtpd(8) + process requests from the tlsmgr(8) server in order to seed its internal pseudo random number generator (PRNG). tls_high_cipherlist (see 'postconf -d' output) @@ -538,41 +544,41 @@ SMTPD(8) SMTPD(8) The OpenSSL cipherlist for "export" or higher grade ciphers. tls_null_cipherlist (eNULL:!aNULL) - 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: smtpd_tls_fingerprint_digest (see 'postconf -d' output) - The message digest algorithm to construct remote SMTP - client-certificate fingerprints or public key fingerprints - (Postfix 2.9 and later) for check_ccert_access and per- + The message digest algorithm to construct remote SMTP + client-certificate fingerprints or public key fingerprints + (Postfix 2.9 and later) for check_ccert_access and per- mit_tls_clientcerts. Available in Postfix version 2.6 and later: smtpd_tls_protocols (see postconf -d output) - TLS protocols accepted by the Postfix SMTP server with oppor- + TLS protocols accepted by the Postfix SMTP server with oppor- tunistic TLS encryption. smtpd_tls_ciphers (medium) - 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. smtpd_tls_eccert_file (empty) - File with the Postfix SMTP server ECDSA certificate in PEM for- + File with the Postfix SMTP server ECDSA certificate in PEM for- mat. smtpd_tls_eckey_file ($smtpd_tls_eccert_file) - 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. smtpd_tls_eecdh_grade (see 'postconf -d' output) - 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. tls_eecdh_strong_curve (prime256v1) - 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. tls_eecdh_ultra_curve (secp384r1) @@ -583,7 +589,7 @@ SMTPD(8) SMTPD(8) tls_preempt_cipherlist (no) 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. tls_disable_workarounds (see 'postconf -d' output) @@ -596,7 +602,7 @@ SMTPD(8) SMTPD(8) Available in Postfix version 3.0 and later: - tls_session_ticket_cipher (Postfix >= 3.0: aes-256-cbc, Postfix < 3.0: + tls_session_ticket_cipher (Postfix >= 3.0: aes-256-cbc, Postfix < 3.0: aes-128-cbc) Algorithm used to encrypt RFC5077 TLS session tickets. @@ -609,26 +615,20 @@ SMTPD(8) SMTPD(8) Available in Postfix version 3.4 and later: smtpd_tls_chain_files (empty) - 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. tls_server_sni_maps (empty) - 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: tls_fast_shutdown_enable (yes) - 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: - - info_log_address_format (external) - The email address form that will be used in non-debug logging - (info, warning, etc.). - Available in Postfix version 3.8 and later: tls_ffdhe_auto_groups (see 'postconf -d' output) diff --git a/postfix/man/man1/posttls-finger.1 b/postfix/man/man1/posttls-finger.1 index 54b72aba2..1e22a03d9 100644 --- a/postfix/man/man1/posttls-finger.1 +++ b/postfix/man/man1/posttls-finger.1 @@ -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 diff --git a/postfix/man/man5/postconf.5 b/postfix/man/man5/postconf.5 index a86e73363..3eeb9388f 100644 --- a/postfix/man/man5/postconf.5 +++ b/postfix/man/man5/postconf.5 @@ -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. diff --git a/postfix/man/man8/smtp.8 b/postfix/man/man8/smtp.8 index fa6138d7f..d2a4ce9ba 100644 --- a/postfix/man/man8/smtp.8 +++ b/postfix/man/man8/smtp.8 @@ -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 diff --git a/postfix/man/man8/smtpd.8 b/postfix/man/man8/smtpd.8 index bc8ec35a5..460293901 100644 --- a/postfix/man/man8/smtpd.8 +++ b/postfix/man/man8/smtpd.8 @@ -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 diff --git a/postfix/mantools/postlink b/postfix/mantools/postlink index 3e07222a2..39057abe5 100755 --- a/postfix/mantools/postlink +++ b/postfix/mantools/postlink @@ -1157,6 +1157,10 @@ while (<>) { s;\blocal_login_sender_maps\b;$&;g; s;\bempty_address_local_login_sender_maps_lookup_key\b;$&;g; + s;\buse_srv_lookup\b;$&;g; + s;\ballow_srv_lookup_fallback\b;$&;g; + s;\bignore_srv_lookup_error\b;$&;g; + # Service-defined parameters... s;\bpolicy_time_limit\b;$&;g; diff --git a/postfix/proto/SASL_README.html b/postfix/proto/SASL_README.html index 3e2025a7a..0b33f3009 100644 --- a/postfix/proto/SASL_README.html +++ b/postfix/proto/SASL_README.html @@ -267,7 +267,7 @@ in /usr/lib/sasl2/.

  • 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 +

  • 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 diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto index a130f95fc..be367b427 100644 --- a/postfix/proto/postconf.proto +++ b/postfix/proto/postconf.proto @@ -7380,7 +7380,7 @@ instead.

    -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.

    @@ -18478,3 +18478,110 @@ Postfix SMTP client will continue delivery after logging a warning. configuration parameter. See there for details.

    This feature is available in Postfix 3.7 and later.

    + +%PARAM use_srv_lookup + +

    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.

    + +

    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.

    + +

    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.

    + +

    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".

    + +
    +/etc/postfix/main.cf:
    +    use_srv_lookup = submission
    +    relayhost = example.com:submission
    +    smtp_tls_security_level = may
    +    ...see SASL_README for sasl configuration...
    +
    + +

    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". +

    + +

    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".

    + +
    +/etc/postfix/main.cf:
    +    use_srv_lookup = submissions
    +    default_transport = smtp-wraptls:example.org:submissions
    +    ...see SASL_README for sasl configuration...
    +
    + +
    +/etc/postfix/master.cf:
    +    smtp-wraptls   unix   ...   ...   ...   ...   ...   smtp
    +        -o { smtp_tls_wrappermode = yes }
    +        -o { smtp_tls_security_level = encrypt }
    +
    + +

    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".

    + +
    +/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...
    +
    + +

    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. +

    + +
    +/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
    +
    + +

    This feature is available in Postfix 3.8 and later.

    + +%PARAM ignore_srv_lookup_error no + +

    When SRV record lookup fails, fall back to MX or IP address +lookup as if SRV record lookup was not enabled. + +

    This feature is available in Postfix 3.8 and later.

    + +%PARAM allow_srv_lookup_fallback 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.

    + +

    This feature is available in Postfix 3.8 and later.

    diff --git a/postfix/proto/stop b/postfix/proto/stop index d663ad9c0..d8dbb3a57 100644 --- a/postfix/proto/stop +++ b/postfix/proto/stop @@ -1570,3 +1570,4 @@ Bugfix https egrep fgrep +SRV diff --git a/postfix/proto/stop.double-history b/postfix/proto/stop.double-history index 072374f68..425aa26bf 100644 --- a/postfix/proto/stop.double-history +++ b/postfix/proto/stop.double-history @@ -16,3 +16,11 @@ 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 diff --git a/postfix/proto/stop.double-proto-html b/postfix/proto/stop.double-proto-html index a7e78243d..c216f9598 100644 --- a/postfix/proto/stop.double-proto-html +++ b/postfix/proto/stop.double-proto-html @@ -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 diff --git a/postfix/proto/stop.spell-cc b/postfix/proto/stop.spell-cc index 9eb8f8a7e..b1fce0d3b 100644 --- a/postfix/proto/stop.spell-cc +++ b/postfix/proto/stop.spell-cc @@ -1789,3 +1789,7 @@ deduplicate digestbyname mdctxPtr ffdhe +Korbar +ign +noport +nopref diff --git a/postfix/proto/stop.spell-history b/postfix/proto/stop.spell-history index 56e38baf7..46e64559b 100644 --- a/postfix/proto/stop.spell-history +++ b/postfix/proto/stop.spell-history @@ -40,3 +40,7 @@ Typofixes segfault Biggs wordsmithing +NOPORT +NOPREF +NOWEIGHT +modernisms diff --git a/postfix/proto/stop.spell-proto-html b/postfix/proto/stop.spell-proto-html index 7a0806880..6d0cb20c7 100644 --- a/postfix/proto/stop.spell-proto-html +++ b/postfix/proto/stop.spell-proto-html @@ -354,3 +354,5 @@ FFDHE dhe ffdhe kDHE +srv +wraptls diff --git a/postfix/src/dns/dns.h b/postfix/src/dns/dns.h index 5f53dbc8f..acc1fb029 100644 --- a/postfix/src/dns/dns.h +++ b/postfix/src/dns/dns.h @@ -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 */ diff --git a/postfix/src/dns/dns_lookup.c b/postfix/src/dns/dns_lookup.c index 1c12a889d..d44cae7ee 100644 --- a/postfix/src/dns/dns_lookup.c +++ b/postfix/src/dns/dns_lookup.c @@ -234,6 +234,10 @@ /* 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) { diff --git a/postfix/src/dns/dns_rr.c b/postfix/src/dns/dns_rr.c index b550788b9..803263599 100644 --- a/postfix/src/dns/dns_rr.c +++ b/postfix/src/dns/dns_rr.c @@ -7,13 +7,15 @@ /* #include /* /* 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; /* @@ -49,6 +51,30 @@ /* 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. @@ -56,10 +82,14 @@ /* 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. /* @@ -81,6 +111,9 @@ /* 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 @@ -90,6 +123,15 @@ /* 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. */ @@ -113,6 +155,7 @@ 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); +} diff --git a/postfix/src/dns/dns_rr_eq_sa.c b/postfix/src/dns/dns_rr_eq_sa.c index 8113d6b26..f553a0323 100644 --- a/postfix/src/dns/dns_rr_eq_sa.c +++ b/postfix/src/dns/dns_rr_eq_sa.c @@ -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); diff --git a/postfix/src/dns/dns_sa_to_rr.c b/postfix/src/dns/dns_sa_to_rr.c index 6b9efcc17..b5dee2091 100644 --- a/postfix/src/dns/dns_sa_to_rr.c +++ b/postfix/src/dns/dns_sa_to_rr.c @@ -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"); diff --git a/postfix/src/dns/dns_str_resflags.c b/postfix/src/dns/dns_str_resflags.c index 472394c3a..793da1c26 100644 --- a/postfix/src/dns/dns_str_resflags.c +++ b/postfix/src/dns/dns_str_resflags.c @@ -21,6 +21,8 @@ /* Google, Inc. /* 111 8th Avenue /* New York, NY 10011, USA +/* +/* Viktor Dukhovni /*--*/ /* @@ -52,11 +54,11 @@ 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 diff --git a/postfix/src/dns/dns_strrecord.c b/postfix/src/dns/dns_strrecord.c index 6b8e9893e..1e3b74389 100644 --- a/postfix/src/dns/dns_strrecord.c +++ b/postfix/src/dns/dns_strrecord.c @@ -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; diff --git a/postfix/src/dns/dns_strtype.c b/postfix/src/dns/dns_strtype.c index 70e59acdc..7eebe3c08 100644 --- a/postfix/src/dns/dns_strtype.c +++ b/postfix/src/dns/dns_strtype.c @@ -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 */ diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index 4df9b7b02..b364850c5 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -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 diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index fcf78608e..d67ef3aac 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * Patches change both the patchlevel and the release date. Snapshots have no * patchlevel; they change the release date only. */ -#define MAIL_RELEASE_DATE "20230128" +#define MAIL_RELEASE_DATE "20230219" #define MAIL_VERSION_NUMBER "3.8" #ifdef SNAPSHOT diff --git a/postfix/src/posttls-finger/posttls-finger.c b/postfix/src/posttls-finger/posttls-finger.c index 5526c408d..2a9efe2db 100644 --- a/postfix/src/posttls-finger/posttls-finger.c +++ b/postfix/src/posttls-finger/posttls-finger.c @@ -237,6 +237,8 @@ /* 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; diff --git a/postfix/src/smtp/lmtp_params.c b/postfix/src/smtp/lmtp_params.c index cc3364642..bca7cd494 100644 --- a/postfix/src/smtp/lmtp_params.c +++ b/postfix/src/smtp/lmtp_params.c @@ -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[] = { @@ -128,6 +129,8 @@ 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[] = { diff --git a/postfix/src/smtp/smtp.c b/postfix/src/smtp/smtp.c index a398dc5ae..e865197ab 100644 --- a/postfix/src/smtp/smtp.c +++ b/postfix/src/smtp/smtp.c @@ -146,6 +146,7 @@ /* 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) @@ -352,6 +353,17 @@ /* 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 */ diff --git a/postfix/src/smtp/smtp.h b/postfix/src/smtp/smtp.h index 742ed300c..0864313b7 100644 --- a/postfix/src/smtp/smtp.h +++ b/postfix/src/smtp/smtp.h @@ -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 */ diff --git a/postfix/src/smtp/smtp_addr.c b/postfix/src/smtp/smtp_addr.c index 2b5c126e5..a31cb38c1 100644 --- a/postfix/src/smtp/smtp_addr.c +++ b/postfix/src/smtp/smtp_addr.c @@ -17,6 +17,15 @@ /* 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(). @@ -44,8 +55,18 @@ /* 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. @@ -66,6 +87,10 @@ /* 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); +} diff --git a/postfix/src/smtp/smtp_addr.h b/postfix/src/smtp/smtp_addr.h index 8f20961e5..60ea2b47e 100644 --- a/postfix/src/smtp/smtp_addr.h +++ b/postfix/src/smtp/smtp_addr.h @@ -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 /*--*/ diff --git a/postfix/src/smtp/smtp_connect.c b/postfix/src/smtp/smtp_connect.c index ed58180f6..68faca18e 100644 --- a/postfix/src/smtp/smtp_connect.c +++ b/postfix/src/smtp/smtp_connect.c @@ -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", diff --git a/postfix/src/smtp/smtp_params.c b/postfix/src/smtp/smtp_params.c index cd54f8fcb..22f4709c1 100644 --- a/postfix/src/smtp/smtp_params.c +++ b/postfix/src/smtp/smtp_params.c @@ -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[] = { @@ -132,6 +133,8 @@ 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[] = { diff --git a/postfix/src/smtp/smtp_reuse.c b/postfix/src/smtp/smtp_reuse.c index f93ba296a..288483f76 100644 --- a/postfix/src/smtp/smtp_reuse.c +++ b/postfix/src/smtp/smtp_reuse.c @@ -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); diff --git a/postfix/src/smtp/smtp_session.c b/postfix/src/smtp/smtp_session.c index 9f1397843..90a0ff1e1 100644 --- a/postfix/src/smtp/smtp_session.c +++ b/postfix/src/smtp/smtp_session.c @@ -129,6 +129,7 @@ #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(); diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index b8d2c52e6..143d44171 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -145,6 +145,11 @@ /* .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. @@ -518,11 +523,6 @@ /* 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 diff --git a/postfix/src/smtpd/smtpd_check.c b/postfix/src/smtpd/smtpd_check.c index 29e8671a4..b6a2aced6 100644 --- a/postfix/src/smtpd/smtpd_check.c +++ b/postfix/src/smtpd/smtpd_check.c @@ -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]) { diff --git a/postfix/src/util/attr.h b/postfix/src/util/attr.h index 067405f58..7cd0cf285 100644 --- a/postfix/src/util/attr.h +++ b/postfix/src/util/attr.h @@ -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); diff --git a/postfix/src/util/sys_defs.h b/postfix/src/util/sys_defs.h index 37e460f9c..924718531 100644 --- a/postfix/src/util/sys_defs.h +++ b/postfix/src/util/sys_defs.h @@ -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 diff --git a/postfix/src/util/unix_send_fd.c b/postfix/src/util/unix_send_fd.c index 1998a7c20..15cc4df60 100644 --- a/postfix/src/util/unix_send_fd.c +++ b/postfix/src/util/unix_send_fd.c @@ -29,6 +29,11 @@ /* 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 */