2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-29 13:18:12 +00:00

postfix-2.6.4-RC2

This commit is contained in:
Wietse Venema 2009-08-07 00:00:00 -05:00 committed by Viktor Dukhovni
parent a6af126373
commit e0e6c0c596
4 changed files with 123 additions and 48 deletions

View File

@ -15270,13 +15270,33 @@ Apologies for any names omitted.
feature can be used meaningfully at any protocol stage. feature can be used meaningfully at any protocol stage.
File: proto/postconf.proto. File: proto/postconf.proto.
20090803 20090805
Workaround: with some local DNS servers including BIND, it Bugfix: don't panic when an unexpected smtpd access map is
is possible that A or MX lookups succeed, while NS lookups specified. File: smtpd/smtpd_check.c.
for the same domains time out. Spammers use this to avoid
access restrictions. To deal with future variations of 20090807
this, check_{client,helo,sender,etc}_{mx,ns,etc}_access no
longer tolerate any lookup failures. Instead, they reply Workaround: NS record lookups for certain domains always
with $access_map_defer_code or $access_map_reject_code as fail, while other queries for those domains always succeed
appropriate. File: smtpd/smtpd_check.c. (and even return replies with NS records as additional
information).
This inconsistency would allow spammers to avoid the Postfix
check_{client,helo,sender,etc}_ns_access restrictions,
because those restrictions have effect only for names that
are known in the DNS.
To address this specific inconsistency, the Postfix
check_{client,etc}_ns_access feature now requires that a
known-in-DNS domain name (or parent thereof) resolves to
at least one name server IP address.
For consistency, check_{client,etc}_mx_access now requires
that a known-in-DNS domain name resolves to at least one
mail server IP address.
The IP addresses thus obtained may or may not be "correct".
There is little to stop an uncooperative DNS server from
lying, especially when the owner of the domain has no
intention to receive email. File: smtpd/smtpd_check.c.

View File

@ -17,18 +17,23 @@ before proceeding.
Incompatibility with Postfix 2.6.4 Incompatibility with Postfix 2.6.4
================================== ==================================
The check_{client,helo,sender,etc}_{mx,ns,etc}_access features no With some domain names, NS record lookups always fail while other
longer tolerate any lookup failures. Instead, they now reply with lookups always succeed (and may even return NS records as additional
$access_map_defer_code or $access_map_reject_code as appropriate. information). This anomaly could be used by evil elements to skip
Postfix check_{client,helo,sender,recipient}_ns_access checks,
because these apply only to domains that are known in the DNS.
The reason for this change is that spammers are using tricks where To address this specific problem, check_{client,etc}_ns_access now
A or MX lookups succeed while NS lookups for the same domains fail, requires that a known-in-DNS domain name (or parent thereof) resolves
depending local DNS infrastructure details. The change deals with to at least one name server IP address.
future variants of this anomalous behavior.
As a side effect, non-existent domain names in HELO commands will For consistency, check_{client,etc}_mx_access now requires that a
now trigger a REJECT action with check_helo_{mx,ns}_access, where known-in-DNS domain name resolves to at least one mail server IP
previously such commands were silently permitted. address.
Keep in mind that these measures provide no hard assurances. There
is little to stop an uncooperative DNS server from lying, especially
when the owner of the domain has no intention to receive email.
Major changes - multi-instance support Major changes - multi-instance support
-------------------------------------- --------------------------------------

View File

@ -20,8 +20,8 @@
* Patches change both the patchlevel and the release date. Snapshots have no * Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only. * patchlevel; they change the release date only.
*/ */
#define MAIL_RELEASE_DATE "20090803" #define MAIL_RELEASE_DATE "20090807"
#define MAIL_VERSION_NUMBER "2.6.4-RC1" #define MAIL_VERSION_NUMBER "2.6.4-RC2"
#ifdef SNAPSHOT #ifdef SNAPSHOT
# define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE # define MAIL_VERSION_DATE "-" MAIL_RELEASE_DATE

View File

@ -2315,8 +2315,13 @@ static int check_access(SMTPD_STATE *state, const char *table, const char *name,
if (msg_verbose) if (msg_verbose)
msg_info("%s: %s", myname, name); msg_info("%s: %s", myname, name);
if ((dict = dict_handle(table)) == 0) if ((dict = dict_handle(table)) == 0) {
msg_panic("%s: dictionary not found: %s", myname, table); msg_warn("%s: unexpected dictionary: %s", myname, table);
value = "451 4.3.5 Server configuration error";
CHK_ACCESS_RETURN(check_table_result(state, table, value, name,
reply_name, reply_class,
def_acl), FOUND);
}
if (flags == 0 || (flags & dict->flags) != 0) { if (flags == 0 || (flags & dict->flags) != 0) {
if ((value = dict_get(dict, name)) != 0) if ((value = dict_get(dict, name)) != 0)
CHK_ACCESS_RETURN(check_table_result(state, table, value, name, CHK_ACCESS_RETURN(check_table_result(state, table, value, name,
@ -2360,8 +2365,13 @@ static int check_domain_access(SMTPD_STATE *state, const char *table,
*/ */
#define CHK_DOMAIN_RETURN(x,y) { *found = y; return(x); } #define CHK_DOMAIN_RETURN(x,y) { *found = y; return(x); }
if ((dict = dict_handle(table)) == 0) if ((dict = dict_handle(table)) == 0) {
msg_panic("%s: dictionary not found: %s", myname, table); msg_warn("%s: unexpected dictionary: %s", myname, table);
value = "451 4.3.5 Server configuration error";
CHK_DOMAIN_RETURN(check_table_result(state, table, value,
domain, reply_name, reply_class,
def_acl), FOUND);
}
for (name = domain; *name != 0; name = next) { for (name = domain; *name != 0; name = next) {
if (flags == 0 || (flags & dict->flags) != 0) { if (flags == 0 || (flags & dict->flags) != 0) {
if ((value = dict_get(dict, name)) != 0) if ((value = dict_get(dict, name)) != 0)
@ -2419,8 +2429,13 @@ static int check_addr_access(SMTPD_STATE *state, const char *table,
#endif #endif
delim = '.'; delim = '.';
if ((dict = dict_handle(table)) == 0) if ((dict = dict_handle(table)) == 0) {
msg_panic("%s: dictionary not found: %s", myname, table); msg_warn("%s: unexpected dictionary: %s", myname, table);
value = "451 4.3.5 Server configuration error";
CHK_ADDR_RETURN(check_table_result(state, table, value, address,
reply_name, reply_class,
def_acl), FOUND);
}
do { do {
if (flags == 0 || (flags & dict->flags) != 0) { if (flags == 0 || (flags & dict->flags) != 0) {
if ((value = dict_get(dict, addr)) != 0) if ((value = dict_get(dict, addr)) != 0)
@ -2500,6 +2515,10 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
struct addrinfo *res; struct addrinfo *res;
int status; int status;
INET_PROTO_INFO *proto_info; INET_PROTO_INFO *proto_info;
const char *saved_domain;
int non_err, soft_err;
int known_name_in_dns;
int ping_status;
/* /*
* Sanity check. * Sanity check.
@ -2554,15 +2573,26 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
* *
* If the domain name exists but no NS record exists, look up parent domain * If the domain name exists but no NS record exists, look up parent domain
* NS records. * NS records.
*
* After the initial lookup fails, do one final DNS sanity check. Reject
* mail when the name exists, but MX lookup produces no valid response or
* NS lookup fails for any reason. Beware, this sanity check provides no
* hard assurance. An uncooperative DNS server may lie about everything,
* including non-existence.
*/ */
#define SOME_DNS_RR_EXISTS(stat, herr) \
((stat) == DNS_OK || (stat) == DNS_INVAL || (herr) == NO_DATA)
saved_domain = domain;
dns_status = dns_lookup(domain, type, 0, &server_list, dns_status = dns_lookup(domain, type, 0, &server_list,
(VSTRING *) 0, (VSTRING *) 0); (VSTRING *) 0, (VSTRING *) 0);
if (dns_status == DNS_NOTFOUND && h_errno == NO_DATA) { known_name_in_dns = SOME_DNS_RR_EXISTS(dns_status, h_errno);
if (dns_status == DNS_NOTFOUND /* Not: h_errno == NO_DATA */ ) {
if (type == T_MX) { if (type == T_MX) {
server_list = dns_rr_create(domain, domain, type, C_IN, 0, 0, server_list = dns_rr_create(domain, domain, type, C_IN, 0, 0,
domain, strlen(domain) + 1); domain, strlen(domain) + 1);
dns_status = DNS_OK; dns_status = DNS_OK;
} else if (type == T_NS) { } else if (type == T_NS && h_errno == NO_DATA) {
while ((domain = strchr(domain, '.')) != 0 && domain[1]) { while ((domain = strchr(domain, '.')) != 0 && domain[1]) {
domain += 1; domain += 1;
dns_status = dns_lookup(domain, type, 0, &server_list, dns_status = dns_lookup(domain, type, 0, &server_list,
@ -2575,14 +2605,23 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
if (dns_status != DNS_OK) { if (dns_status != DNS_OK) {
msg_warn("Unable to look up %s host for %s: %s", dns_strtype(type), msg_warn("Unable to look up %s host for %s: %s", dns_strtype(type),
domain && domain[1] ? domain : name, dns_strerror(h_errno)); domain && domain[1] ? domain : name, dns_strerror(h_errno));
/* No mercy for DNS failure. */ if (known_name_in_dns == 0) {
return (smtpd_check_reject(state, MAIL_ERROR_POLICY, /* With hostile DNS, an address query is more likely to work. */
dns_status == DNS_NOTFOUND ? ping_status = dns_lookup_l(saved_domain, 0, (DNS_RR **) 0,
var_map_reject_code : var_map_defer_code, (VSTRING *) 0, (VSTRING *) 0,
smtpd_dsn_fix("4.1.8", reply_class), DNS_REQ_FLAG_STOP_OK,
"<%s>: %s rejected: %s", RR_ADDR_TYPES, 0);
reply_name, reply_class, known_name_in_dns = SOME_DNS_RR_EXISTS(ping_status, h_errno);
"Domain not found")); }
if (known_name_in_dns)
return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
dns_status == DNS_RETRY ?
var_map_defer_code : var_map_reject_code,
smtpd_dsn_fix("4.1.8", reply_class),
"<%s>: %s rejected: %s",
reply_name, reply_class,
"Domain not found"));
return (SMTPD_CHECK_DUNNO);
} }
/* /*
@ -2594,10 +2633,19 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
* Check the hostnames first, then the addresses. * Check the hostnames first, then the addresses.
*/ */
proto_info = inet_proto_info(); proto_info = inet_proto_info();
non_err = soft_err = 0;
for (server = server_list; server != 0; server = server->next) { for (server = server_list; server != 0; server = server->next) {
if (msg_verbose) if (msg_verbose)
msg_info("%s: %s hostname check: %s", msg_info("%s: %s hostname check: %s",
myname, dns_strtype(type), (char *) server->data); myname, dns_strtype(type), (char *) server->data);
if (valid_hostaddr((char *) server->data, DONT_GRIPE)) {
non_err = 1;
if ((status = check_addr_access(state, table, (char *) server->data,
FULL, &found, reply_name, reply_class,
def_acl)) != 0 || found)
CHECK_SERVER_RETURN(status);
continue;
}
if ((status = check_domain_access(state, table, (char *) server->data, if ((status = check_domain_access(state, table, (char *) server->data,
FULL, &found, reply_name, reply_class, FULL, &found, reply_name, reply_class,
def_acl)) != 0 || found) def_acl)) != 0 || found)
@ -2607,17 +2655,11 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
msg_warn("Unable to look up %s host %s for %s %s: %s", msg_warn("Unable to look up %s host %s for %s %s: %s",
dns_strtype(type), (char *) server->data, dns_strtype(type), (char *) server->data,
reply_class, reply_name, MAI_STRERROR(aierr)); reply_class, reply_name, MAI_STRERROR(aierr));
/* No mercy for DNS failure. */ if (aierr == EAI_AGAIN || aierr == EAI_SYSTEM)
status = smtpd_check_reject(state, soft_err = 1;
MAIL_ERROR_POLICY, continue;
aierr == EAI_NONAME ?
var_map_reject_code : var_map_defer_code,
smtpd_dsn_fix("4.1.8", reply_class),
"<%s>: %s rejected: %s",
reply_name, reply_class,
"Domain not found");
CHECK_SERVER_RETURN(status);
} }
non_err = 1;
/* Now we must also free the addrinfo result. */ /* Now we must also free the addrinfo result. */
if (msg_verbose) if (msg_verbose)
msg_info("%s: %s host address check: %s", msg_info("%s: %s host address check: %s",
@ -2641,7 +2683,15 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
} }
freeaddrinfo(res0); /* 200412 */ freeaddrinfo(res0); /* 200412 */
} }
CHECK_SERVER_RETURN(SMTPD_CHECK_DUNNO); status = non_err ? SMTPD_CHECK_DUNNO :
smtpd_check_reject(state, MAIL_ERROR_POLICY,
soft_err ? var_map_defer_code :
var_map_reject_code,
smtpd_dsn_fix("4.1.8", reply_class),
"<%s>: %s rejected: %s",
reply_name, reply_class,
"Domain not found");
CHECK_SERVER_RETURN(status);
} }
/* check_ccert_access - access for TLS clients by certificate fingerprint */ /* check_ccert_access - access for TLS clients by certificate fingerprint */