Change HELO-verify forward case from byname to bydns and add DNSSEC tracking
authorJeremy Harris <jgh146exb@wizmail.org>
Tue, 19 May 2015 19:28:42 +0000 (20:28 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Tue, 19 May 2015 21:36:35 +0000 (22:36 +0100)
14 files changed:
doc/doc-docbook/spec.xfpt
doc/doc-txt/ChangeLog
src/src/dns.c
src/src/expand.c
src/src/globals.c
src/src/globals.h
src/src/host.c
src/src/smtp_in.c
test/confs/0608 [new file with mode: 0644]
test/dnszones-src/db.test.ex
test/log/0608 [new file with mode: 0644]
test/scripts/0000-Basic/0608 [new file with mode: 0644]
test/stderr/0070
test/stdout/0608 [new file with mode: 0644]

index c1668c7ac472d236c72e4856275ebff858b5244a..7527121819d3a74e530fc3aa46511fca415dccce 100644 (file)
@@ -11415,7 +11415,7 @@ This variable contains the numerical value of the Exim user id.
 
 .new
 .vitem &$exim_version$&
 
 .new
 .vitem &$exim_version$&
-.vindex "&$exim_uid$&"
+.vindex "&$exim_version$&"
 This variable contains the version string of the Exim build.
 The first character is a major version number, currently 4.
 Then after a dot, the next group of digits is a minor version number.
 This variable contains the version string of the Exim build.
 The first character is a major version number, currently 4.
 Then after a dot, the next group of digits is a minor version number.
@@ -11681,6 +11681,7 @@ the space value is -1. See also the &%check_log_space%& option.
 .vindex "&$lookup_dnssec_authenticated$&"
 This variable is set after a DNS lookup done by
 a dnsdb lookup expansion, dnslookup router or smtp transport.
 .vindex "&$lookup_dnssec_authenticated$&"
 This variable is set after a DNS lookup done by
 a dnsdb lookup expansion, dnslookup router or smtp transport.
+.cindex "DNS" "DNSSEC"
 It will be empty if &(DNSSEC)& was not requested,
 &"no"& if the result was not labelled as authenticated data
 and &"yes"& if it was.
 It will be empty if &(DNSSEC)& was not requested,
 &"no"& if the result was not labelled as authenticated data
 and &"yes"& if it was.
@@ -12198,6 +12199,14 @@ verification either failed or was not requested. A host name in parentheses is
 the argument of a HELO or EHLO command. This is omitted if it is identical to
 the verified host name or to the host's IP address in square brackets.
 
 the argument of a HELO or EHLO command. This is omitted if it is identical to
 the verified host name or to the host's IP address in square brackets.
 
+.new
+.vitem &$sender_helo_dnssec$&
+.vindex "&$sender_helo_dnssec$&"
+This boolean variable is true if a successful HELO verification was
+.cindex "DNS" "DNSSEC"
+done using DNS information the resolver library stated was authenticatied data.
+.wen
+
 .vitem &$sender_helo_name$&
 .vindex "&$sender_helo_name$&"
 When a message is received from a remote host that has issued a HELO or EHLO
 .vitem &$sender_helo_name$&
 .vindex "&$sender_helo_name$&"
 When a message is received from a remote host that has issued a HELO or EHLO
@@ -12227,6 +12236,7 @@ resolver library states that both
 the reverse and forward DNS were authenticated data.  At all
 other times, this variable is false.
 
 the reverse and forward DNS were authenticated data.  At all
 other times, this variable is false.
 
+.cindex "DNS" "DNSSEC"
 It is likely that you will need to coerce DNSSEC support on in the resolver
 library, by setting:
 .code
 It is likely that you will need to coerce DNSSEC support on in the resolver
 library, by setting:
 .code
@@ -14535,14 +14545,17 @@ is an IP literal matching the calling address of the host, or
 matches the host name that Exim obtains by doing a reverse lookup of the
 calling host address, or
 .next
 matches the host name that Exim obtains by doing a reverse lookup of the
 calling host address, or
 .next
-when looked up using &[gethostbyname()]& (or &[getipnodebyname()]& when
-available) yields the calling host address.
+when looked up in DNS yields the calling host address.
 .endlist
 
 However, the EHLO or HELO command is not rejected if any of the checks
 fail. Processing continues, but the result of the check is remembered, and can
 be detected later in an ACL by the &`verify = helo`& condition.
 
 .endlist
 
 However, the EHLO or HELO command is not rejected if any of the checks
 fail. Processing continues, but the result of the check is remembered, and can
 be detected later in an ACL by the &`verify = helo`& condition.
 
+If DNS was used for successful verification, the variable
+.cindex "DNS" "DNSSEC"
+&$helo_verify_dnssec$& records the DNSSEC status of the lookups.
+
 .option helo_verify_hosts main "host list&!!" unset
 .cindex "HELO verifying" "mandatory"
 .cindex "EHLO" "verifying, mandatory"
 .option helo_verify_hosts main "host list&!!" unset
 .cindex "HELO verifying" "mandatory"
 .cindex "EHLO" "verifying, mandatory"
index c6825d5be4b17177b2c52292ab86971ef2d0e8bd..a0d964926b6f23c8479fdf03c6f80bda92fece04 100644 (file)
@@ -106,6 +106,9 @@ JH/29 Bug 1632: Removed the word "rejected" from line logged for ACL discards.
 JH/30 Check the forward DNS lookup for DNSSEC, in addition to the reverse,
       when evaluating $sender_host_dnssec.
 
 JH/30 Check the forward DNS lookup for DNSSEC, in addition to the reverse,
       when evaluating $sender_host_dnssec.
 
+JH/31 Check the HELO verification lookup for DNSSEC, adding new
+      $sender_helo_dnssec variable.
+
 
 Exim version 4.85
 -----------------
 
 Exim version 4.85
 -----------------
index ad98a9d4e420003bf003f64c204bac1356b70ade..79c4ed3fca701eb234989a7865944d9256084065 100644 (file)
@@ -796,7 +796,7 @@ for (i = 0; i < 10; i++)
 
   cname_rr.data = type_rr.data = NULL;
   for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
 
   cname_rr.data = type_rr.data = NULL;
   for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
-       rr != NULL;
+       rr;
        rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
     {
     if (rr->type == type)
        rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
     {
     if (rr->type == type)
@@ -895,25 +895,25 @@ switch (type)
   {
   /* The "mx hosts only" type doesn't require any special action here */
   case T_MXH:
   {
   /* The "mx hosts only" type doesn't require any special action here */
   case T_MXH:
-       return dns_lookup(dnsa, name, T_MX, fully_qualified_name);
+    return dns_lookup(dnsa, name, T_MX, fully_qualified_name);
 
   /* Find nameservers for the domain or the nearest enclosing zone, excluding
   the root servers. */
   case T_ZNS:
 
   /* Find nameservers for the domain or the nearest enclosing zone, excluding
   the root servers. */
   case T_ZNS:
-       type = T_NS;
-       /* FALLTHROUGH */
+    type = T_NS;
+    /* FALLTHROUGH */
   case T_SOA:
   case T_SOA:
-       {
-       const uschar *d = name;
-       while (d != 0)
-         {
-         int rc = dns_lookup(dnsa, d, type, fully_qualified_name);
-         if (rc != DNS_NOMATCH && rc != DNS_NODATA) return rc;
-         while (*d != 0 && *d != '.') d++;
-         if (*d++ == 0) break;
-         }
-       return DNS_NOMATCH;
-       }
+    {
+    const uschar *d = name;
+    while (d != 0)
+      {
+      int rc = dns_lookup(dnsa, d, type, fully_qualified_name);
+      if (rc != DNS_NOMATCH && rc != DNS_NODATA) return rc;
+      while (*d != 0 && *d != '.') d++;
+      if (*d++ == 0) break;
+      }
+    return DNS_NOMATCH;
+    }
 
   /* Try to look up the Client SMTP Authorization SRV record for the name. If
   there isn't one, search from the top downwards for a CSA record in a parent
 
   /* Try to look up the Client SMTP Authorization SRV record for the name. If
   there isn't one, search from the top downwards for a CSA record in a parent
@@ -922,148 +922,147 @@ switch (type)
   can tell whether to look at the explicit authorization field or the subdomain
   assertion field. */
   case T_CSA:
   can tell whether to look at the explicit authorization field or the subdomain
   assertion field. */
   case T_CSA:
-       {
-       uschar *srvname, *namesuff, *tld, *p;
-       int priority, weight, port;
-       int limit, rc, i;
-       BOOL ipv6;
-       dns_record *rr;
-       dns_scan dnss;
-
-       DEBUG(D_dns) debug_printf("CSA lookup of %s\n", name);
-
-       srvname = string_sprintf("_client._smtp.%s", name);
-       rc = dns_lookup(dnsa, srvname, T_SRV, NULL);
-       if (rc == DNS_SUCCEED || rc == DNS_AGAIN)
-         {
-         if (rc == DNS_SUCCEED) *fully_qualified_name = string_copy(name);
-         return rc;
-         }
+    {
+    uschar *srvname, *namesuff, *tld, *p;
+    int priority, weight, port;
+    int limit, rc, i;
+    BOOL ipv6;
+    dns_record *rr;
+    dns_scan dnss;
+
+    DEBUG(D_dns) debug_printf("CSA lookup of %s\n", name);
+
+    srvname = string_sprintf("_client._smtp.%s", name);
+    rc = dns_lookup(dnsa, srvname, T_SRV, NULL);
+    if (rc == DNS_SUCCEED || rc == DNS_AGAIN)
+      {
+      if (rc == DNS_SUCCEED) *fully_qualified_name = string_copy(name);
+      return rc;
+      }
 
 
-       /* Search for CSA subdomain assertion SRV records from the top downwards,
-       starting with the 2nd level domain. This order maximizes cache-friendliness.
-       We skip the top level domains to avoid loading their nameservers and because
-       we know they'll never have CSA SRV records. */
+    /* Search for CSA subdomain assertion SRV records from the top downwards,
+    starting with the 2nd level domain. This order maximizes cache-friendliness.
+    We skip the top level domains to avoid loading their nameservers and because
+    we know they'll never have CSA SRV records. */
 
 
-       namesuff = Ustrrchr(name, '.');
-       if (namesuff == NULL) return DNS_NOMATCH;
+    namesuff = Ustrrchr(name, '.');
+    if (namesuff == NULL) return DNS_NOMATCH;
+    tld = namesuff + 1;
+    ipv6 = FALSE;
+    limit = dns_csa_search_limit;
+
+    /* Use more appropriate search parameters if we are in the reverse DNS. */
+
+    if (strcmpic(namesuff, US".arpa") == 0)
+      if (namesuff - 8 > name && strcmpic(namesuff - 8, US".in-addr.arpa") == 0)
+       {
+       namesuff -= 8;
        tld = namesuff + 1;
        tld = namesuff + 1;
-       ipv6 = FALSE;
-       limit = dns_csa_search_limit;
+       limit = 3;
+       }
+      else if (namesuff - 4 > name && strcmpic(namesuff - 4, US".ip6.arpa") == 0)
+       {
+       namesuff -= 4;
+       tld = namesuff + 1;
+       ipv6 = TRUE;
+       limit = 3;
+       }
 
 
-       /* Use more appropriate search parameters if we are in the reverse DNS. */
+    DEBUG(D_dns) debug_printf("CSA TLD %s\n", tld);
 
 
-       if (strcmpic(namesuff, US".arpa") == 0)
-         {
-         if (namesuff - 8 > name && strcmpic(namesuff - 8, US".in-addr.arpa") == 0)
-               {
-               namesuff -= 8;
-               tld = namesuff + 1;
-               limit = 3;
-               }
-         else if (namesuff - 4 > name && strcmpic(namesuff - 4, US".ip6.arpa") == 0)
-               {
-               namesuff -= 4;
-               tld = namesuff + 1;
-               ipv6 = TRUE;
-               limit = 3;
-               }
-         }
+    /* Do not perform the search if the top level or 2nd level domains do not
+    exist. This is quite common, and when it occurs all the search queries would
+    go to the root or TLD name servers, which is not friendly. So we check the
+    AUTHORITY section; if it contains the root's SOA record or the TLD's SOA then
+    the TLD or the 2LD (respectively) doesn't exist and we can skip the search.
+    If the TLD and the 2LD exist but the explicit CSA record lookup failed, then
+    the AUTHORITY SOA will be the 2LD's or a subdomain thereof. */
+
+    if (rc == DNS_NOMATCH)
+      {
+      /* This is really gross. The successful return value from res_search() is
+      the packet length, which is stored in dnsa->answerlen. If we get a
+      negative DNS reply then res_search() returns -1, which causes the bounds
+      checks for name decompression to fail when it is treated as a packet
+      length, which in turn causes the authority search to fail. The correct
+      packet length has been lost inside libresolv, so we have to guess a
+      replacement value. (The only way to fix this properly would be to
+      re-implement res_search() and res_query() so that they don't muddle their
+      success and packet length return values.) For added safety we only reset
+      the packet length if the packet header looks plausible. */
+
+      HEADER *h = (HEADER *)dnsa->answer;
+      if (h->qr == 1 && h->opcode == QUERY && h->tc == 0
+         && (h->rcode == NOERROR || h->rcode == NXDOMAIN)
+         && ntohs(h->qdcount) == 1 && ntohs(h->ancount) == 0
+         && ntohs(h->nscount) >= 1)
+           dnsa->answerlen = MAXPACKET;
+
+      for (rr = dns_next_rr(dnsa, &dnss, RESET_AUTHORITY);
+          rr;
+          rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)
+         )
+       if (rr->type != T_SOA) continue;
+       else if (strcmpic(rr->name, US"") == 0 ||
+                strcmpic(rr->name, tld) == 0) return DNS_NOMATCH;
+       else break;
+      }
 
 
-       DEBUG(D_dns) debug_printf("CSA TLD %s\n", tld);
+    for (i = 0; i < limit; i++)
+      {
+      if (ipv6)
+       {
+       /* Scan through the IPv6 reverse DNS in chunks of 16 bits worth of IP
+       address, i.e. 4 hex chars and 4 dots, i.e. 8 chars. */
+       namesuff -= 8;
+       if (namesuff <= name) return DNS_NOMATCH;
+       }
+      else
+       /* Find the start of the preceding domain name label. */
+       do
+         if (--namesuff <= name) return DNS_NOMATCH;
+       while (*namesuff != '.');
+
+      DEBUG(D_dns) debug_printf("CSA parent search at %s\n", namesuff + 1);
+
+      srvname = string_sprintf("_client._smtp.%s", namesuff + 1);
+      rc = dns_lookup(dnsa, srvname, T_SRV, NULL);
+      if (rc == DNS_AGAIN) return rc;
+      if (rc != DNS_SUCCEED) continue;
+
+      /* Check that the SRV record we have found is worth returning. We don't
+      just return the first one we find, because some lower level SRV record
+      might make stricter assertions than its parent domain. */
+
+      for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
+          rr;
+          rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
+       {
+       if (rr->type != T_SRV) continue;
 
 
-       /* Do not perform the search if the top level or 2nd level domains do not
-       exist. This is quite common, and when it occurs all the search queries would
-       go to the root or TLD name servers, which is not friendly. So we check the
-       AUTHORITY section; if it contains the root's SOA record or the TLD's SOA then
-       the TLD or the 2LD (respectively) doesn't exist and we can skip the search.
-       If the TLD and the 2LD exist but the explicit CSA record lookup failed, then
-       the AUTHORITY SOA will be the 2LD's or a subdomain thereof. */
+       /* Extract the numerical SRV fields (p is incremented) */
+       p = rr->data;
+       GETSHORT(priority, p);
+       GETSHORT(weight, p);    weight = weight; /* compiler quietening */
+       GETSHORT(port, p);
 
 
-       if (rc == DNS_NOMATCH)
-         {
-         /* This is really gross. The successful return value from res_search() is
-         the packet length, which is stored in dnsa->answerlen. If we get a
-         negative DNS reply then res_search() returns -1, which causes the bounds
-         checks for name decompression to fail when it is treated as a packet
-         length, which in turn causes the authority search to fail. The correct
-         packet length has been lost inside libresolv, so we have to guess a
-         replacement value. (The only way to fix this properly would be to
-         re-implement res_search() and res_query() so that they don't muddle their
-         success and packet length return values.) For added safety we only reset
-         the packet length if the packet header looks plausible. */
-
-         HEADER *h = (HEADER *)dnsa->answer;
-         if (h->qr == 1 && h->opcode == QUERY && h->tc == 0
-                 && (h->rcode == NOERROR || h->rcode == NXDOMAIN)
-                 && ntohs(h->qdcount) == 1 && ntohs(h->ancount) == 0
-                 && ntohs(h->nscount) >= 1)
-               dnsa->answerlen = MAXPACKET;
-
-         for (rr = dns_next_rr(dnsa, &dnss, RESET_AUTHORITY);
-                  rr != NULL;
-                  rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
-               if (rr->type != T_SOA) continue;
-               else if (strcmpic(rr->name, US"") == 0 ||
-                                strcmpic(rr->name, tld) == 0) return DNS_NOMATCH;
-               else break;
-         }
+       /* Check the CSA version number */
+       if (priority != 1) continue;
 
 
-       for (i = 0; i < limit; i++)
+       /* If it's making an interesting assertion, return this response. */
+       if (port & 1)
          {
          {
-         if (ipv6)
-               {
-               /* Scan through the IPv6 reverse DNS in chunks of 16 bits worth of IP
-               address, i.e. 4 hex chars and 4 dots, i.e. 8 chars. */
-               namesuff -= 8;
-               if (namesuff <= name) return DNS_NOMATCH;
-               }
-         else
-               /* Find the start of the preceding domain name label. */
-               do
-                 if (--namesuff <= name) return DNS_NOMATCH;
-               while (*namesuff != '.');
-
-         DEBUG(D_dns) debug_printf("CSA parent search at %s\n", namesuff + 1);
-
-         srvname = string_sprintf("_client._smtp.%s", namesuff + 1);
-         rc = dns_lookup(dnsa, srvname, T_SRV, NULL);
-         if (rc == DNS_AGAIN) return rc;
-         if (rc != DNS_SUCCEED) continue;
-
-         /* Check that the SRV record we have found is worth returning. We don't
-         just return the first one we find, because some lower level SRV record
-         might make stricter assertions than its parent domain. */
-
-         for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
-                  rr != NULL;
-                  rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
-               {
-               if (rr->type != T_SRV) continue;
-
-               /* Extract the numerical SRV fields (p is incremented) */
-               p = rr->data;
-               GETSHORT(priority, p);
-               GETSHORT(weight, p);    weight = weight; /* compiler quietening */
-               GETSHORT(port, p);
-
-               /* Check the CSA version number */
-               if (priority != 1) continue;
-
-               /* If it's making an interesting assertion, return this response. */
-               if (port & 1)
-                 {
-                 *fully_qualified_name = namesuff + 1;
-                 return DNS_SUCCEED;
-                 }
-               }
+         *fully_qualified_name = namesuff + 1;
+         return DNS_SUCCEED;
          }
          }
-       return DNS_NOMATCH;
        }
        }
+      }
+    return DNS_NOMATCH;
+    }
 
   default:
 
   default:
-       if (type >= 0)
-         return dns_lookup(dnsa, name, type, fully_qualified_name);
+    if (type >= 0)
+      return dns_lookup(dnsa, name, type, fully_qualified_name);
   }
 
 /* Control should never reach here */
   }
 
 /* Control should never reach here */
index 2092701630b254008d68dfdef81dd869ebd6f131..7e10ee5533407debae9c015d2708de03cf2106ae 100644 (file)
@@ -648,6 +648,7 @@ static var_entry var_table[] = {
   { "sender_address_local_part", vtype_localpart, &sender_address },
   { "sender_data",         vtype_stringptr,   &sender_data },
   { "sender_fullhost",     vtype_stringptr,   &sender_fullhost },
   { "sender_address_local_part", vtype_localpart, &sender_address },
   { "sender_data",         vtype_stringptr,   &sender_data },
   { "sender_fullhost",     vtype_stringptr,   &sender_fullhost },
+  { "sender_helo_dnssec",  vtype_bool,        &sender_helo_dnssec },
   { "sender_helo_name",    vtype_stringptr,   &sender_helo_name },
   { "sender_host_address", vtype_stringptr,   &sender_host_address },
   { "sender_host_authenticated",vtype_stringptr, &sender_host_authenticated },
   { "sender_helo_name",    vtype_stringptr,   &sender_helo_name },
   { "sender_host_address", vtype_stringptr,   &sender_host_address },
   { "sender_host_authenticated",vtype_stringptr, &sender_host_authenticated },
index 3cbbbd311be3c4cf86604a9255fed1f227656987..c0d03daaabaf0eef29921de93a4f10b82c68c404 100644 (file)
@@ -1202,6 +1202,7 @@ uschar *sender_address_unrewritten = NULL;
 uschar *sender_data            = NULL;
 unsigned int sender_domain_cache[(MAX_NAMED_LIST * 2)/32];
 uschar *sender_fullhost        = NULL;
 uschar *sender_data            = NULL;
 unsigned int sender_domain_cache[(MAX_NAMED_LIST * 2)/32];
 uschar *sender_fullhost        = NULL;
+BOOL    sender_helo_dnssec     = FALSE;
 uschar *sender_helo_name       = NULL;
 uschar **sender_host_aliases   = &no_aliases;
 uschar *sender_host_address    = NULL;
 uschar *sender_helo_name       = NULL;
 uschar **sender_host_aliases   = &no_aliases;
 uschar *sender_host_address    = NULL;
index d90854cbe57af1aa780589fbcfbbda10462db138..1aca0714f779dd35fbe8d48a23de494b657cc38c 100644 (file)
@@ -755,6 +755,7 @@ extern uschar *sender_address_unrewritten; /* Set if rewritten by verify */
 extern uschar *sender_data;            /* lookup result for senders */
 extern unsigned int sender_domain_cache[(MAX_NAMED_LIST * 2)/32]; /* Cache bits for sender domain */
 extern uschar *sender_fullhost;        /* Sender host name + address */
 extern uschar *sender_data;            /* lookup result for senders */
 extern unsigned int sender_domain_cache[(MAX_NAMED_LIST * 2)/32]; /* Cache bits for sender domain */
 extern uschar *sender_fullhost;        /* Sender host name + address */
+extern BOOL    sender_helo_dnssec;     /* True if HELO verify used DNS and was DNSSEC */
 extern uschar *sender_helo_name;       /* Host name from HELO/EHLO */
 extern uschar **sender_host_aliases;   /* Points to list of alias names */
 extern unsigned int sender_host_cache[(MAX_NAMED_LIST * 2)/32]; /* Cache bits for incoming host */
 extern uschar *sender_helo_name;       /* Host name from HELO/EHLO */
 extern uschar **sender_host_aliases;   /* Points to list of alias names */
 extern unsigned int sender_host_cache[(MAX_NAMED_LIST * 2)/32]; /* Cache bits for incoming host */
index 4772a7c6c3199bf2e5e19330de1e1d3f5c32e40d..5629d7db2948086149089e5162775c91ad3b45f2 100644 (file)
@@ -1668,11 +1668,10 @@ while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer))))
       store_pool = POOL_PERM;        /* Save names in permanent storage */
 
       for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
       store_pool = POOL_PERM;        /* Save names in permanent storage */
 
       for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
-           rr != NULL;
+           rr;
            rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
            rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
-        {
-        if (rr->type == T_PTR) count++;
-        }
+        if (rr->type == T_PTR)
+         count++;
 
       /* Get store for the list of aliases. For compatibility with
       gethostbyaddr, we make an empty list if there are none. */
 
       /* Get store for the list of aliases. For compatibility with
       gethostbyaddr, we make an empty list if there are none. */
@@ -1682,7 +1681,7 @@ while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer))))
       /* Re-scan and extract the names */
 
       for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
       /* Re-scan and extract the names */
 
       for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
-           rr != NULL;
+           rr;
            rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
         {
         uschar *s = NULL;
            rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
         {
         uschar *s = NULL;
index b2f8b0fc808c0fabe0baf958dcda02bbeaa669ad..aa3936288e262a224a117af8ce3613693c291f5b 100644 (file)
@@ -3003,31 +3003,25 @@ else
 
   /* If a host name is known, check it and all its aliases. */
 
 
   /* If a host name is known, check it and all its aliases. */
 
-  if (sender_host_name != NULL)
-    {
-    helo_verified = strcmpic(sender_host_name, sender_helo_name) == 0;
-
-    if (helo_verified)
+  if (sender_host_name)
+    if ((helo_verified = strcmpic(sender_host_name, sender_helo_name) == 0))
       {
       {
-      /*XXX have sender_host_dnssec */
+      sender_helo_dnssec = sender_host_dnssec;
       HDEBUG(D_receive) debug_printf("matched host name\n");
       }
     else
       {
       uschar **aliases = sender_host_aliases;
       HDEBUG(D_receive) debug_printf("matched host name\n");
       }
     else
       {
       uschar **aliases = sender_host_aliases;
-      while (*aliases != NULL)
-        {
-        helo_verified = strcmpic(*aliases++, sender_helo_name) == 0;
-        if (helo_verified) break;
-      /*XXX have sender_host_dnssec */
-        }
-      HDEBUG(D_receive)
-        {
-        if (helo_verified)
+      while (*aliases)
+        if ((helo_verified = strcmpic(*aliases++, sender_helo_name) == 0))
+         {
+         sender_helo_dnssec = sender_host_dnssec;
+         break;
+         }
+
+      HDEBUG(D_receive) if (helo_verified)
           debug_printf("matched alias %s\n", *(--aliases));
           debug_printf("matched alias %s\n", *(--aliases));
-        }
       }
       }
-    }
 
   /* Final attempt: try a forward lookup of the helo name */
 
 
   /* Final attempt: try a forward lookup of the helo name */
 
@@ -3035,31 +3029,34 @@ else
     {
     int rc;
     host_item h;
     {
     int rc;
     host_item h;
+    dnssec_domains d;
+    host_item *hh;
+
     h.name = sender_helo_name;
     h.address = NULL;
     h.mx = MX_NONE;
     h.next = NULL;
     h.name = sender_helo_name;
     h.address = NULL;
     h.mx = MX_NONE;
     h.next = NULL;
+    d.request = US"*";
+    d.require = US"";
+
     HDEBUG(D_receive) debug_printf("getting IP address for %s\n",
       sender_helo_name);
     HDEBUG(D_receive) debug_printf("getting IP address for %s\n",
       sender_helo_name);
-/*XXX would like to determine dnssec status here */
-/* need to change to bydns */
-    rc = host_find_byname(&h, NULL, 0, NULL, TRUE);
+    rc = host_find_bydns(&h, NULL, HOST_FIND_BY_A,
+                         NULL, NULL, NULL, &d, NULL, NULL);
     if (rc == HOST_FOUND || rc == HOST_FOUND_LOCAL)
     if (rc == HOST_FOUND || rc == HOST_FOUND_LOCAL)
-      {
-      host_item *hh = &h;
-      while (hh != NULL)
-        {
+      for (hh = &h; hh; hh = hh->next)
         if (Ustrcmp(hh->address, sender_host_address) == 0)
           {
           helo_verified = TRUE;
         if (Ustrcmp(hh->address, sender_host_address) == 0)
           {
           helo_verified = TRUE;
+         if (h.dnssec == DS_YES) sender_helo_dnssec = TRUE;
           HDEBUG(D_receive)
           HDEBUG(D_receive)
-            debug_printf("IP address for %s matches calling address\n",
-              sender_helo_name);
+           {
+            debug_printf("IP address for %s matches calling address\n"
+             "Forward DNS security status: %sverified\n",
+              sender_helo_name, sender_helo_dnssec ? "" : "un");
+           }
           break;
           }
           break;
           }
-        hh = hh->next;
-        }
-      }
     }
   }
 
     }
   }
 
@@ -3473,7 +3470,7 @@ while (done <= 0)
       now obsolescent, since the verification can now be requested selectively
       at ACL time. */
 
       now obsolescent, since the verification can now be requested selectively
       at ACL time. */
 
-      helo_verified = helo_verify_failed = FALSE;
+      helo_verified = helo_verify_failed = sender_helo_dnssec = FALSE;
       if (helo_required || helo_verify)
         {
         BOOL tempfail = !smtp_verify_helo();
       if (helo_required || helo_verify)
         {
         BOOL tempfail = !smtp_verify_helo();
diff --git a/test/confs/0608 b/test/confs/0608
new file mode 100644 (file)
index 0000000..d04dc36
--- /dev/null
@@ -0,0 +1,24 @@
+# Exim test configuration 0608
+
+exim_path = EXIM_PATH
+host_lookup_order = bydns
+primary_hostname = myhost.test.ex
+spool_directory = DIR/spool
+log_file_path = DIR/spool/log/%slog
+gecos_pattern = ""
+gecos_name = CALLER_NAME
+
+# ----- Main settings -----
+
+acl_smtp_helo = check_helo
+
+
+# ----- ACLs -----
+
+begin acl
+
+check_helo:
+  require verify = helo
+  accept  logwrite = helo $sender_helo_name dnssec <$sender_helo_dnssec>
+
+# End
index da084529f7159a2c5cbfe90177c62176cc2faf83..9cc709eccfc7a2de169b1c4d042d89f0b70cd6d6 100644 (file)
@@ -406,6 +406,8 @@ DNSSEC mx-sec-a-sec     MX 5 a-sec
 a-unsec       A V4NET.0.0.100
 DNSSEC a-sec  A V4NET.0.0.100
 
 a-unsec       A V4NET.0.0.100
 DNSSEC a-sec  A V4NET.0.0.100
 
+DNSSEC l-sec  A 127.0.0.1
+
 ; ------- Testing DANE ------------
 
 ; full suite dns chain, sha512
 ; ------- Testing DANE ------------
 
 ; full suite dns chain, sha512
diff --git a/test/log/0608 b/test/log/0608
new file mode 100644 (file)
index 0000000..7d807e8
--- /dev/null
@@ -0,0 +1,3 @@
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 helo localhost dnssec <no>
+1999-03-02 09:44:33 helo l-sec dnssec <yes>
diff --git a/test/scripts/0000-Basic/0608 b/test/scripts/0000-Basic/0608
new file mode 100644 (file)
index 0000000..1715fd2
--- /dev/null
@@ -0,0 +1,20 @@
+# HELO verify dnssec
+# Exim test configuration 0608
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+client 127.0.0.1 PORT_D
+??? 220
+HELO localhost
+??? 250
+****
+#
+client 127.0.0.1 PORT_D
+??? 220
+HELO l-sec
+??? 250
+****
+#
+killdaemon
+no_msglog_check
index 2bf1e9cdf49afc85b734364d90d3607d02fca0f8..c50f93612c83c21a79b2a6dd170ca21521baa9fd 100644 (file)
@@ -137,10 +137,10 @@ MUNGED: ::1 will be omitted in what follows
 >>> matched alias ten-3-alias.test.ex
 >>> verifying EHLO/HELO argument "ten-3xtra.test.ex"
 >>> getting IP address for ten-3xtra.test.ex
 >>> matched alias ten-3-alias.test.ex
 >>> verifying EHLO/HELO argument "ten-3xtra.test.ex"
 >>> getting IP address for ten-3xtra.test.ex
-MUNGED: ::1 will be omitted in what follows
->>> get[host|ipnode]byname[2] looked up these IP addresses:
->>>   name=ten-3xtra.test.ex address=V4NET.0.0.3
+>>> ten-3xtra.test.ex in ""? no (end of list)
+>>> ten-3xtra.test.ex in "*"? yes (matched "*")
 >>> IP address for ten-3xtra.test.ex matches calling address
 >>> IP address for ten-3xtra.test.ex matches calling address
+>>> Forward DNS security status: unverified
 >>> host in hosts_connection_nolog? no (option unset)
 >>> host in host_lookup? no (option unset)
 >>> host in host_reject_connection? no (option unset)
 >>> host in hosts_connection_nolog? no (option unset)
 >>> host in host_lookup? no (option unset)
 >>> host in host_reject_connection? no (option unset)
@@ -158,7 +158,8 @@ MUNGED: ::1 will be omitted in what follows
 >>> checking addresses for ten-1.test.ex
 >>>   V4NET.0.0.1 OK
 >>> getting IP address for rhubarb
 >>> checking addresses for ten-1.test.ex
 >>>   V4NET.0.0.1 OK
 >>> getting IP address for rhubarb
->>> no IP address found for host rhubarb (during SMTP connection from (rhubarb) [V4NET.0.0.1])
+>>> rhubarb in ""? no (end of list)
+>>> rhubarb in "*"? yes (matched "*")
 LOG: rejected "EHLO rhubarb" from (rhubarb) [V4NET.0.0.1]
 >>> host in hosts_connection_nolog? no (option unset)
 >>> host in host_lookup? no (option unset)
 LOG: rejected "EHLO rhubarb" from (rhubarb) [V4NET.0.0.1]
 >>> host in hosts_connection_nolog? no (option unset)
 >>> host in host_lookup? no (option unset)
@@ -178,7 +179,8 @@ MUNGED: ::1 will be omitted in what follows
 >>> looking up host name for 99.99.99.99
 >>> Test harness: host name lookup returns DEFER
 >>> getting IP address for rhubarb
 >>> looking up host name for 99.99.99.99
 >>> Test harness: host name lookup returns DEFER
 >>> getting IP address for rhubarb
->>> no IP address found for host rhubarb (during SMTP connection from (rhubarb) [99.99.99.99])
+>>> rhubarb in ""? no (end of list)
+>>> rhubarb in "*"? yes (matched "*")
 LOG: temporarily rejected "EHLO rhubarb" from (rhubarb) [99.99.99.99]
 >>> host in hosts_connection_nolog? no (option unset)
 >>> host in host_lookup? no (option unset)
 LOG: temporarily rejected "EHLO rhubarb" from (rhubarb) [99.99.99.99]
 >>> host in hosts_connection_nolog? no (option unset)
 >>> host in host_lookup? no (option unset)
@@ -264,7 +266,8 @@ MUNGED: ::1 will be omitted in what follows
 >>> looking up host name for 99.99.99.99
 >>> Test harness: host name lookup returns DEFER
 >>> getting IP address for rhubarb
 >>> looking up host name for 99.99.99.99
 >>> Test harness: host name lookup returns DEFER
 >>> getting IP address for rhubarb
->>> no IP address found for host rhubarb (during SMTP connection from (rhubarb) [99.99.99.99])
+>>> rhubarb in ""? no (end of list)
+>>> rhubarb in "*"? yes (matched "*")
 >>> require: condition test failed in ACL "rcpt"
 >>> end of ACL "rcpt": not OK
 LOG: H=(rhubarb) [99.99.99.99] F=<a@b> rejected RCPT <c@d>: helo not verified
 >>> require: condition test failed in ACL "rcpt"
 >>> end of ACL "rcpt": not OK
 LOG: H=(rhubarb) [99.99.99.99] F=<a@b> rejected RCPT <c@d>: helo not verified
diff --git a/test/stdout/0608 b/test/stdout/0608
new file mode 100644 (file)
index 0000000..9681d83
--- /dev/null
@@ -0,0 +1,14 @@
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> HELO localhost
+??? 250
+<<< 250 myhost.test.ex Hello localhost [127.0.0.1]
+End of script
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> HELO l-sec
+??? 250
+<<< 250 myhost.test.ex Hello localhost [127.0.0.1]
+End of script