From: Wietse Venema
The LMTP-specific version of the smtp_balance_inet_protocols +configuration parameter. See there for details.
+ +This feature is available in Postfix 3.3 and later.
+ +When a remote destination resolves to a combination of IPv4 and +IPv6 addresses, ensure that the Postfix SMTP client can try both +address types before it runs into the smtp_mx_address_limit.
+ +This avoids an interoperability problem when a destination resolves +to primarily IPv6 addresses, the smtp_address_limit feature eliminates +most or all IPv4 addresses, and the destination is not reachable over +IPv6.
+ +This feature is available in Postfix 3.3 and later.
+ +This feature is available in Postfix 3.2 and later.
+ +%PARAM smtp_balance_inet_protocols yes + +When a remote destination resolves to a combination of IPv4 and +IPv6 addresses, ensure that the Postfix SMTP client can try both +address types before it runs into the smtp_mx_address_limit.
+ +This avoids an interoperability problem when a destination resolves +to primarily IPv6 addresses, the smtp_address_limit feature eliminates +most or all IPv4 addresses, and the destination is not reachable over +IPv6.
+ +This feature is available in Postfix 3.3 and later.
+ +%PARAM lmtp_balance_inet_protocols yes + +The LMTP-specific version of the smtp_balance_inet_protocols +configuration parameter. See there for details.
+ +This feature is available in Postfix 3.3 and later.
diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h index 3cc94a02b..be6970a28 100644 --- a/postfix/src/global/mail_params.h +++ b/postfix/src/global/mail_params.h @@ -1704,6 +1704,12 @@ extern char *var_smtp_sasl_tlsv_opts; #define DEF_SMTP_DUMMY_MAIL_AUTH 0 extern bool var_smtp_dummy_mail_auth; +#define VAR_LMTP_BALANCE_INET_PROTO "lmtp_balance_inet_protocols" +#define DEF_LMTP_BALANCE_INET_PROTO DEF_SMTP_BALANCE_INET_PROTO +#define VAR_SMTP_BALANCE_INET_PROTO "smtp_balance_inet_protocols" +#define DEF_SMTP_BALANCE_INET_PROTO 1 +extern bool var_smtp_balance_inet_proto; + /* * LMTP server. The soft error limit determines how many errors an LMTP * client may make before we start to slow down; the hard error limit diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 8b99fb8c6..9ab7a1874 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 "20170502" +#define MAIL_RELEASE_DATE "20170505" #define MAIL_VERSION_NUMBER "3.3" #ifdef SNAPSHOT diff --git a/postfix/src/smtp/lmtp_params.c b/postfix/src/smtp/lmtp_params.c index 732d55434..68d611e26 100644 --- a/postfix/src/smtp/lmtp_params.c +++ b/postfix/src/smtp/lmtp_params.c @@ -121,5 +121,6 @@ VAR_LMTP_ASSUME_FINAL, DEF_LMTP_ASSUME_FINAL, &var_lmtp_assume_final, VAR_LMTP_REC_DEADLINE, DEF_LMTP_REC_DEADLINE, &var_smtp_rec_deadline, 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, 0, }; diff --git a/postfix/src/smtp/smtp.c b/postfix/src/smtp/smtp.c index fd90bd13d..a93fa01b5 100644 --- a/postfix/src/smtp/smtp.c +++ b/postfix/src/smtp/smtp.c @@ -263,6 +263,12 @@ /* deliveries. /* .IP "\fBsmtp_dns_reply_filter (empty)\fR" /* Optional filter for Postfix SMTP client DNS lookup results. +/* .PP +/* Available in Postfix version 3.3 and later: +/* .IP "\fBsmtp_balance_inet_protocols (yes)\fR" +/* When a remote destination resolves to a combination of IPv4 and +/* IPv6 addresses, ensure that the Postfix SMTP client can try both +/* address types before it runs into the smtp_mx_address_limit. /* MIME PROCESSING CONTROLS /* .ad /* .fi @@ -934,6 +940,7 @@ bool var_smtp_rec_deadline; bool var_smtp_dummy_mail_auth; char *var_smtp_dsn_filter; char *var_smtp_dns_re_filter; +bool var_smtp_balance_inet_proto; /* Special handling of 535 AUTH errors. */ char *var_smtp_sasl_auth_cache_name; diff --git a/postfix/src/smtp/smtp_addr.c b/postfix/src/smtp/smtp_addr.c index 789a21806..46652a5e6 100644 --- a/postfix/src/smtp/smtp_addr.c +++ b/postfix/src/smtp/smtp_addr.c @@ -354,6 +354,119 @@ static DNS_RR *smtp_truncate_self(DNS_RR *addr_list, unsigned pref) return (addr_list); } +/* smtp_balance_inet_proto - balance IPv4/6 protocols within address limit */ + +static DNS_RR *smtp_balance_inet_proto(DNS_RR *addr_list, int misc_flags, + int addr_limit) +{ + const char myname[] = "smtp_balance_inet_proto"; + DNS_RR *rr; + DNS_RR *result_list; + DNS_RR *next; + int v6_count; + int v4_count; + int v6_target, v4_target; + int *p; + + /* + * Precondition: the input is sorted by MX preference (not necessarily IP + * address family preference), and addresses with the same or worse + * preference than 'myself' have been eliminated. Postcondition: the + * relative list order is unchanged, but some elements are removed. + */ + + /* + * Count the number of IPv6 and IPv4 addresses. + */ + for (v4_count = v6_count = 0, rr = addr_list; rr != 0; rr = rr->next) { + if (rr->type == T_A) { + v4_count++; + } else if (rr->type == T_AAAA) { + v6_count++; + } else { + msg_panic("%s: unexpected record type: %s", + myname, dns_strtype(rr->type)); + } + } + + /* + * Ensure that one address type will not out-crowd the other, while + * enforcing the address count limit. This works around a current problem + * where some destination announces primarily IPv6 MX addresses, the + * smtp_address_limit eliminates most or all IPv4 addresses, and the + * destination is not reachable over IPv6. + * + * Maybe: do all smtp_mx_address_limit enforcement here, and remove + * pre-existing enforcement elsewhere. That would obsolete the + * smtp_balance_inet_protocols configuration parameter. + */ + if (v4_count > 0 && v6_count > 0 && v4_count + v6_count > addr_limit) { + + /*- + * Decide how many IPv6 and IPv4 addresses to keep. The code below + * has three branches, corresponding to the regions R1, R2 and R3 + * in the figure. + * + * L = addr_limit + * X = excluded by condition (v4_count + v6_count > addr_limit) + * + * v4_count + * ^ + * | + * L \ R1 + * |X\ | + * |XXX\ | + * |XXXXX\ | R2 + * L/2 +-------\------- + * |XXXXXXX|X\ + * |XXXXXXX|XXX\ R3 + * |XXXXXXX|XXXXX\ + * 0 +-------+-------\--> v6_count + * 0 L/2 L + */ + if (v6_count <= addr_limit / 2) { /* Region R1 */ + v6_target = v6_count; + v4_target = addr_limit - v6_target; + } else if (v4_count <= addr_limit / 2) {/* Region R3 */ + v4_target = v4_count; + v6_target = addr_limit - v4_target; + } else { /* Region R2 */ + /* v4_count > addr_limit / 2 && v6_count > addr_limit / 2 */ + v4_target = (addr_limit + (addr_list->type == T_A)) / 2; + v6_target = addr_limit - v4_target; + } + if (msg_verbose) + msg_info("v6_target=%d, v4_target=%d", v6_target, v4_target); + + /* Enforce the address count targets. */ + result_list = 0; + for (rr = addr_list; rr != 0; rr = next) { + next = rr->next; + rr->next = 0; + if (rr->type == T_A) { + p = &v4_target; + } else if (rr->type == T_AAAA) { + p = &v6_target; + } else { + msg_panic("%s: unexpected record type: %s", + myname, dns_strtype(rr->type)); + } + if (*p > 0) { + result_list = dns_rr_append(result_list, rr); + *p -= 1; + } else { + dns_rr_free(rr); + } + } + if (v4_target > 0 || v6_target > 0) + msg_panic("%s: bad target count: v4_target=%d, v6_target=%d", + myname, v4_target, v6_target); + if (msg_verbose) + smtp_print_addr("smtp_balance_inet_proto result", result_list); + } + return (result_list); +} + /* smtp_domain_addr - mail exchanger address lookup */ DNS_RR *smtp_domain_addr(const char *name, DNS_RR **mxrr, int misc_flags, @@ -498,9 +611,13 @@ DNS_RR *smtp_domain_addr(const char *name, DNS_RR **mxrr, int misc_flags, ((flags) & SMTP_MISC_FLAG_PREF_IPV4) ? dns_rr_compare_pref_ipv4 : \ dns_rr_compare_pref_any) - if (addr_list && addr_list->next && var_smtp_rand_addr) { - addr_list = dns_rr_shuffle(addr_list); + if (addr_list && addr_list->next) { + if (var_smtp_rand_addr) + addr_list = dns_rr_shuffle(addr_list); addr_list = dns_rr_sort(addr_list, SMTP_COMPARE_ADDR(misc_flags)); + if (var_smtp_balance_inet_proto) + addr_list = smtp_balance_inet_proto(addr_list, misc_flags, + var_smtp_mxaddr_limit); } break; case DNS_NOTFOUND: @@ -558,6 +675,9 @@ DNS_RR *smtp_host_addr(const char *host, int misc_flags, DSN_BUF *why) /* The following changes the order of equal-preference hosts. */ if (inet_proto_info()->ai_family_list[1] != 0) addr_list = dns_rr_sort(addr_list, SMTP_COMPARE_ADDR(misc_flags)); + if (var_smtp_balance_inet_proto) + addr_list = smtp_balance_inet_proto(addr_list, misc_flags, + var_smtp_mxaddr_limit); } if (msg_verbose) smtp_print_addr(host, addr_list); diff --git a/postfix/src/smtp/smtp_params.c b/postfix/src/smtp/smtp_params.c index d8628831d..ed5ea455b 100644 --- a/postfix/src/smtp/smtp_params.c +++ b/postfix/src/smtp/smtp_params.c @@ -125,5 +125,6 @@ VAR_LMTP_ASSUME_FINAL, DEF_LMTP_ASSUME_FINAL, &var_lmtp_assume_final, VAR_SMTP_REC_DEADLINE, DEF_SMTP_REC_DEADLINE, &var_smtp_rec_deadline, 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, 0, };