]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.7-20090807
authorWietse Venema <wietse@porcupine.org>
Fri, 7 Aug 2009 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:35:39 +0000 (06:35 +0000)
postfix/HISTORY
postfix/RELEASE_NOTES
postfix/src/global/mail_version.h
postfix/src/smtpd/smtpd_check.c

index 7996d16b0eecc5e7370966dbfaeb78b617101939..b7925f75cc41bfe7e663d721cb13363858e17507 100644 (file)
@@ -15336,22 +15336,33 @@ Apologies for any names omitted.
        Bugfix: don't panic when an unexpected smtpd access map is
        specified. File: smtpd/smtpd_check.c.
 
+20090807
+
        Workaround: NS record lookups for certain domains always
        fail, while other queries for those domains always succeed
        (and even return replies with NS records as additional
        information).
 
-       This specific inconsistency would allow spammers to avoid
-       the Postfix check_{client,helo,sender,etc}_ns_access
-       restrictions, because those restrictions have effect only
-       for NS records that can be looked up in the DNS.
+       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
-       reject_unknown_helo_hostname, reject_unknown_sender_domain
-       and reject_unknown_recipient_domain restrictions now require
-       that a domain has NS records that resolve to at least one
-       IP address, and they now accept only MX records that resolve
-       to at least one IP address; those addresses may or may not
-       be "correct". Postfix has no code to determine whether the
-       SMTP client name has a resolvable NS or MX record.  File:
-       smtpd/smtpd_check.c.
+       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.
+
+       In addition, reject_unknown_helo_hostname,
+       reject_unknown_sender_domain now require that an MX record
+       resolves to at least one IP address. Until now, the existence
+       of an MX record was sufficient.
+
+       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.
index 5fabd25743513204e27f92f158facd6f0cf21f91..8875c6b3ccc002dbde430ccb9d8dacd1c7b88021 100644 (file)
@@ -14,22 +14,31 @@ specifies the release date of a stable release or snapshot release.
 If you upgrade from Postfix 2.5 or earlier, read RELEASE_NOTES-2.6
 before proceeding.
 
-Incompatibility with snapshot 20090805
+Incompatibility with snapshot 20090807
 ======================================
 
 With some domain names, NS record lookups always fail while other
-lookups always succeed (and often return NS records as additional
+lookups always succeed (and may even return NS records as additional
 information).  This anomaly could be used by evil elements to skip
 Postfix check_{client,helo,sender,recipient}_ns_access checks,
-because those apply only domains with an NS record in the DNS.
-
-To address this specific problem, the reject_unknown_helo_hostname,
-reject_unknown_sender_domain and reject_unknown_recipient_domain
-features now require that a domain name has NS records that resolve
-to at least one IP address, and they now accept only MX records
-that resolve to at least one IP address; those addresses may or may
-not be "correct". Postfix has no code to determine whether the
-SMTP client name has a resolvable NS or MX record.
+because these apply only to domains that are known in the DNS.
+
+To address this specific problem, check_{client,etc}_ns_access 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.
+
+In addition, reject_unknown_helo_hostname, reject_unknown_sender_domain
+and reject_unknown_recipient_domain now require that an MX record
+resolves to at least one IP address.  Until now, the existence of
+an MX record was sufficient.
+
+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.
 
 Incompatibility with snapshot 20090606
 ======================================
index ce299ad39a2055b4e3853fd740e71645f65873d8..b4977fc56af371e527cf54091ce340526706c5ac 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20090805"
+#define MAIL_RELEASE_DATE      "20090807"
 #define MAIL_VERSION_NUMBER    "2.7"
 
 #ifdef SNAPSHOT
index 33bc092370c8b9caeaa67b07cf09b3664957ae9a..939429dee4c3d979991c2bcd6aa62d18abbb8e22 100644 (file)
@@ -1166,12 +1166,12 @@ static int resolve_server_list(const char *name, int type,
      */
     dns_status = dns_lookup(domain, type, 0, &server_list,
                            (VSTRING *) 0, (VSTRING *) 0);
-    if (dns_status == DNS_NOTFOUND && h_errno == NO_DATA) {
+    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);
            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]) {
                domain += 1;
                dns_status = dns_lookup(domain, type, 0, &server_list,
@@ -1232,8 +1232,10 @@ static int reject_unknown_hostname(SMTPD_STATE *state, char *name,
      * check_server_access() wants to check.
      */
     dns_status = resolve_server_list(name, T_MX, reply_name, reply_class);
+#ifdef REQUIRE_NS_FOR_REJECT_UNKNOWN_DOMAIN_CHECK
     if (dns_status == DNS_OK)
        dns_status = resolve_server_list(name, T_NS, reply_name, reply_class);
+#endif
     if (dns_status != DNS_OK) {                        /* incl. DNS_INVAL */
        if (dns_status != DNS_RETRY)
            return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
@@ -1268,8 +1270,10 @@ static int reject_unknown_mailhost(SMTPD_STATE *state, const char *name,
      * check_server_access() wants to check.
      */
     dns_status = resolve_server_list(name, T_MX, reply_name, reply_class);
+#ifdef REQUIRE_NS_FOR_REJECT_UNKNOWN_DOMAIN_CHECK
     if (dns_status == DNS_OK)
        dns_status = resolve_server_list(name, T_NS, reply_name, reply_class);
+#endif
     if (dns_status != DNS_OK) {                        /* incl. DNS_INVAL */
        if (dns_status != DNS_RETRY)
            return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
@@ -2590,6 +2594,10 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
     struct addrinfo *res;
     int     status;
     INET_PROTO_INFO *proto_info;
+    const char *saved_domain;
+    int     non_err, soft_err;
+    int     known_name_in_dns;
+    int     ping_status;
 
     /*
      * Sanity check.
@@ -2644,15 +2652,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
      * 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,
                            (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) {
            server_list = dns_rr_create(domain, domain, type, C_IN, 0, 0,
                                        domain, strlen(domain) + 1);
            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]) {
                domain += 1;
                dns_status = dns_lookup(domain, type, 0, &server_list,
@@ -2665,6 +2684,22 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
     if (dns_status != DNS_OK) {
        msg_warn("Unable to look up %s host for %s: %s", dns_strtype(type),
                 domain && domain[1] ? domain : name, dns_strerror(h_errno));
+       if (known_name_in_dns == 0) {
+           /* With hostile DNS, an address query is more likely to work. */
+           ping_status = dns_lookup_l(saved_domain, 0, (DNS_RR **) 0,
+                                      (VSTRING *) 0, (VSTRING *) 0,
+                                      DNS_REQ_FLAG_STOP_OK,
+                                      CHECK_RR_ADDR_TYPES, 0);
+           known_name_in_dns = SOME_DNS_RR_EXISTS(ping_status, h_errno);
+       }
+       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);
     }
 
@@ -2677,11 +2712,13 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
      * Check the hostnames first, then the addresses.
      */
     proto_info = inet_proto_info();
+    non_err = soft_err = 0;
     for (server = server_list; server != 0; server = server->next) {
        if (msg_verbose)
            msg_info("%s: %s hostname check: %s",
                     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)
@@ -2697,8 +2734,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",
                     dns_strtype(type), (char *) server->data,
                     reply_class, reply_name, MAI_STRERROR(aierr));
+           if (aierr == EAI_AGAIN || aierr == EAI_SYSTEM)
+               soft_err = 1;
            continue;
        }
+       non_err = 1;
        /* Now we must also free the addrinfo result. */
        if (msg_verbose)
            msg_info("%s: %s host address check: %s",
@@ -2722,7 +2762,15 @@ static int check_server_access(SMTPD_STATE *state, const char *table,
        }
        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 */