LDAP: Fix debug messages
[exim.git] / src / src / verify.c
index d85ef3b4f16d12e4d70cd9ee5119f9e63524b901..6c228abbf55f9d6d7d5a97f1da46625b3c145595 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2014 */
+/* Copyright (c) University of Cambridge 1995 - 2015 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Functions concerned with verifying things. The original code for callout
@@ -21,6 +21,7 @@ uschar ctbuffer[8192];
 /* Structure for caching DNSBL lookups */
 
 typedef struct dnsbl_cache_block {
+  time_t expiry;
   dns_address *rhs;
   uschar *text;
   int rc;
@@ -70,7 +71,7 @@ cache_record = dbfn_read_with_length(dbm_file, key, &length);
 
 if (cache_record == NULL)
   {
-  HDEBUG(D_verify) debug_printf("callout cache: no %s record found\n", type);
+  HDEBUG(D_verify) debug_printf("callout cache: no %s record found for %s\n", type, key);
   return NULL;
   }
 
@@ -84,7 +85,7 @@ now = time(NULL);
 
 if (now - cache_record->time_stamp > expire)
   {
-  HDEBUG(D_verify) debug_printf("callout cache: %s record expired\n", type);
+  HDEBUG(D_verify) debug_printf("callout cache: %s record expired for %s\n", type, key);
   return NULL;
   }
 
@@ -111,7 +112,7 @@ if (type[0] == 'd' && cache_record->result != ccache_reject)
     cache_record->random_result = ccache_unknown;
   }
 
-HDEBUG(D_verify) debug_printf("callout cache: found %s record\n", type);
+HDEBUG(D_verify) debug_printf("callout cache: found %s record for %s\n", type, key);
 return cache_record;
 }
 
@@ -173,6 +174,9 @@ dbdata_callout_cache new_domain_record;
 dbdata_callout_cache_address new_address_record;
 host_item *host;
 time_t callout_start_time;
+#ifdef EXPERIMENTAL_INTERNATIONAL
+BOOL utf8_offered = FALSE;
+#endif
 
 new_domain_record.result = ccache_unknown;
 new_domain_record.postmaster_result = ccache_unknown;
@@ -440,7 +444,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
 
          host_af = (Ustrchr(host->address, ':') == NULL)? AF_INET:AF_INET6;
 
-         if (!smtp_get_interface(tf->interface, host_af, addr, NULL, &interface,
+         if (!smtp_get_interface(tf->interface, host_af, addr, &interface,
                  US"callout") ||
              !smtp_get_port(tf->port, addr, &port, US"callout"))
            log_write(0, LOG_MAIN|LOG_PANIC, "<%s>: %s", addr->address,
@@ -575,9 +579,10 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
     deliver_domain = addr->domain;
     transport_name = addr->transport->name;
 
-    if (!smtp_get_interface(tf->interface, host_af, addr, NULL, &interface,
-            US"callout") ||
-        !smtp_get_port(tf->port, addr, &port, US"callout"))
+    if (  !smtp_get_interface(tf->interface, host_af, addr, &interface,
+            US"callout")
+       || !smtp_get_port(tf->port, addr, &port, US"callout")
+       )
       log_write(0, LOG_MAIN|LOG_PANIC, "<%s>: %s", addr->address,
         addr->message);
 
@@ -588,35 +593,6 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
 
     HDEBUG(D_verify) debug_printf("interface=%s port=%d\n", interface, port);
 
-#if defined(SUPPORT_TLS) && defined(EXPERIMENTAL_DANE)
-      {
-      int rc;
-
-      tls_out.dane_verified = FALSE;
-      tls_out.tlsa_usage = 0;
-
-      dane_required =
-       verify_check_given_host(&ob->hosts_require_dane, host) == OK;
-
-      if (host->dnssec == DS_YES)
-       {
-       if(  dane_required
-         || verify_check_given_host(&ob->hosts_try_dane, host) == OK
-         )
-         if ((rc = tlsa_lookup(host, &tlsa_dnsa, dane_required, &dane)) != OK)
-           return rc;
-       }
-      else if (dane_required)
-       {
-       log_write(0, LOG_MAIN, "DANE error: %s lookup not DNSSEC", host->name);
-       return FAIL;
-       }
-
-      if (dane)
-       ob->tls_tempfail_tryclear = FALSE;
-      }
-#endif  /*DANE*/
-
     /* Set up the buffer for reading SMTP response packets. */
 
     inblock.buffer = inbuffer;
@@ -653,6 +629,36 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
       continue;
       }
 
+#if defined(SUPPORT_TLS) && defined(EXPERIMENTAL_DANE)
+      {
+      int rc;
+
+      tls_out.dane_verified = FALSE;
+      tls_out.tlsa_usage = 0;
+
+      dane_required =
+       verify_check_given_host(&ob->hosts_require_dane, host) == OK;
+
+      if (host->dnssec == DS_YES)
+       {
+       if(  (  dane_required
+            || verify_check_given_host(&ob->hosts_try_dane, host) == OK
+            )
+         && (rc = tlsa_lookup(host, &tlsa_dnsa, dane_required, &dane)) != OK
+         )
+         return rc;
+       }
+      else if (dane_required)
+       {
+       log_write(0, LOG_MAIN, "DANE error: %s lookup not DNSSEC", host->name);
+       return FAIL;
+       }
+
+      if (dane)
+       ob->tls_tempfail_tryclear = FALSE;
+      }
+#endif  /*DANE*/
+
     /* Expand the helo_data string to find the host name to use. */
 
     if (tf->helo_data != NULL)
@@ -918,6 +924,40 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
         }
       }
 
+#ifdef EXPERIMENTAL_INTERNATIONAL
+    else if (  addr->prop.utf8_msg
+           && !addr->prop.utf8_downcvt
+           && !(  esmtp
+               && (  regex_UTF8
+                  || ( (regex_UTF8 = regex_must_compile(
+                         US"\\n250[\\s\\-]SMTPUTF8(\\s|\\n|$)", FALSE, TRUE)),
+                     TRUE
+                  )  )
+               && (  (utf8_offered = pcre_exec(regex_UTF8, NULL,
+                           CS responsebuffer, Ustrlen(responsebuffer),
+                           0, PCRE_EOPT, NULL, 0) >= 0)
+                  || addr->prop.utf8_downcvt_maybe
+           )   )  )
+      {
+      HDEBUG(D_acl|D_v) debug_printf("utf8 required but not offered\n");
+      errno = ERRNO_UTF8_FWD;
+      setflag(addr, af_verify_nsfail);
+      done = FALSE;
+      }
+    else if (  addr->prop.utf8_msg
+           && (addr->prop.utf8_downcvt || !utf8_offered)
+           && (setflag(addr, af_utf8_downcvt),
+               from_address = string_address_utf8_to_alabel(from_address,
+                                     &addr->message),
+               addr->message
+           )  )
+      {
+      errno = ERRNO_EXPANDFAIL;
+      setflag(addr, af_verify_nsfail);
+      done = FALSE;
+      }
+#endif
+
     /* If we haven't authenticated, but are required to, give up. */
     /* Try to AUTH */
 
@@ -935,7 +975,13 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
       ( (addr->auth_sndr = client_authenticated_sender),
 
     /* Send the MAIL command */
-        (smtp_write_command(&outblock, FALSE, "MAIL FROM:<%s>%s\r\n",
+        (smtp_write_command(&outblock, FALSE,
+#ifdef EXPERIMENTAL_INTERNATIONAL
+         addr->prop.utf8_msg && !addr->prop.utf8_downcvt
+         ? "MAIL FROM:<%s>%s SMTPUTF8\r\n"
+         :
+#endif
+           "MAIL FROM:<%s>%s\r\n",
           from_address, responsebuffer) >= 0)
       )  &&
 
@@ -974,6 +1020,23 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
 
     else
       {
+      const uschar * rcpt_domain = addr->domain;
+
+#ifdef EXPERIMENTAL_INTERNATIONAL
+      uschar * errstr = NULL;
+      if (  testflag(addr, af_utf8_downcvt)
+        && (rcpt_domain = string_domain_utf8_to_alabel(rcpt_domain,
+                                   &errstr), errstr)
+        )
+       {
+       addr->message = errstr;
+       errno = ERRNO_EXPANDFAIL;
+       setflag(addr, af_verify_nsfail);
+       done = FALSE;
+       rcpt_domain = US"";  /*XXX errorhandling! */
+       }
+#endif
+
       new_domain_record.result =
         (old_domain_cache_result == ccache_reject_mfnull)?
           ccache_reject_mfnull: ccache_accept;
@@ -986,7 +1049,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
         BOOL random_ok =
           smtp_write_command(&outblock, FALSE,
             "RCPT TO:<%.1000s@%.1000s>\r\n", random_local_part,
-            addr->domain) >= 0 &&
+            rcpt_domain) >= 0 &&
           smtp_read_response(&inblock, randombuffer,
             sizeof(randombuffer), '2', callout);
 
@@ -1020,7 +1083,13 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
             smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer),
               '2', callout) &&
 
-            smtp_write_command(&outblock, FALSE, "MAIL FROM:<%s>\r\n",
+            smtp_write_command(&outblock, FALSE,
+#ifdef EXPERIMENTAL_INTERNATIONAL
+             addr->prop.utf8_msg && !addr->prop.utf8_downcvt
+             ? "MAIL FROM:<%s> SMTPUTF8\r\n"
+             :
+#endif
+               "MAIL FROM:<%s>\r\n",
               from_address) >= 0 &&
             smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer),
               '2', callout);
@@ -1052,11 +1121,27 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
         /* Get the rcpt_include_affixes flag from the transport if there is one,
         but assume FALSE if there is not. */
 
+       uschar * rcpt = transport_rcpt_address(addr,
+              addr->transport ? addr->transport->rcpt_include_affixes : FALSE);
+
+#ifdef EXPERIMENTAL_INTERNATIONAL
+       /*XXX should the conversion be moved into transport_rcpt_address() ? */
+       uschar * dummy_errstr = NULL;
+       if (  testflag(addr, af_utf8_downcvt)
+          && (rcpt = string_address_utf8_to_alabel(rcpt, &dummy_errstr),
+              dummy_errstr
+          )  )
+       {
+       errno = ERRNO_EXPANDFAIL;
+       *failure_ptr = US"recipient";
+       done = FALSE;
+       }
+       else
+#endif
+
         done =
           smtp_write_command(&outblock, FALSE, "RCPT TO:<%.1000s>\r\n",
-            transport_rcpt_address(addr,
-              (addr->transport == NULL)? FALSE :
-               addr->transport->rcpt_include_affixes)) >= 0 &&
+            rcpt) >= 0 &&
           smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer),
             '2', callout);
 
@@ -1093,7 +1178,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
 
             ((
             smtp_write_command(&outblock, FALSE,
-              "RCPT TO:<postmaster@%.1000s>\r\n", addr->domain) >= 0 &&
+              "RCPT TO:<postmaster@%.1000s>\r\n", rcpt_domain) >= 0 &&
             smtp_read_response(&inblock, responsebuffer,
               sizeof(responsebuffer), '2', callout)
             )
@@ -1144,6 +1229,21 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
         HDEBUG(D_verify) debug_printf("SMTP timeout\n");
         send_quit = FALSE;
         }
+#ifdef EXPERIMENTAL_INTERNATIONAL
+      else if (errno == ERRNO_UTF8_FWD)
+       {
+       extern int acl_where;   /* src/acl.c */
+       errno = 0;
+       addr->message = string_sprintf(
+           "response to \"%s\" from %s [%s] did not include SMTPUTF8",
+            big_buffer, host->name, host->address);
+        addr->user_message = acl_where == ACL_WHERE_RCPT
+         ? US"533 mailbox name not allowed"
+         : US"550 mailbox unavailable";
+       yield = FAIL;
+       done = TRUE;
+       }
+#endif
       else if (errno == 0)
         {
         if (*responsebuffer == 0) Ustrcpy(responsebuffer, US"connection dropped");
@@ -1213,8 +1313,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
 #endif
       (void)close(inblock.sock);
 #ifdef EXPERIMENTAL_EVENT
-      (void) event_raise(addr->transport->event_action,
-                             US"tcp:close", NULL);
+      (void) event_raise(addr->transport->event_action, US"tcp:close", NULL);
 #endif
       }
 
@@ -1614,7 +1713,7 @@ if (addr != vaddr)
   vaddr->user_message = addr->user_message;
   vaddr->basic_errno = addr->basic_errno;
   vaddr->more_errno = addr->more_errno;
-  vaddr->p.address_data = addr->p.address_data;
+  vaddr->prop.address_data = addr->prop.address_data;
   copyflag(vaddr, addr, af_pass_message);
   }
 return yield;
@@ -1875,8 +1974,8 @@ while (addr_new != NULL)
 
   /* Just in case some router parameter refers to it. */
 
-  return_path = (addr->p.errors_address != NULL)?
-    addr->p.errors_address : sender_address;
+  return_path = (addr->prop.errors_address != NULL)?
+    addr->prop.errors_address : sender_address;
 
   /* Split the address into domain and local part, handling the %-hack if
   necessary, and then route it. While routing a sender address, set
@@ -1904,6 +2003,7 @@ while (addr_new != NULL)
     if (callout > 0)
       {
       host_item *host_list = addr->host_list;
+      transport_instance * tp;
 
       /* Make up some data for use in the case where there is no remote
       transport. */
@@ -1925,9 +2025,9 @@ while (addr_new != NULL)
       transport's options, so as to mimic what would happen if we were really
       sending a message to this address. */
 
-      if (addr->transport != NULL && !addr->transport->info->local)
+      if ((tp = addr->transport) && !tp->info->local)
         {
-        (void)(addr->transport->setup)(addr->transport, addr, &tf, 0, 0, NULL);
+        (void)(tp->setup)(tp, addr, &tf, 0, 0, NULL);
 
         /* If the transport has hosts and the router does not, or if the
         transport is configured to override the router's hosts, we must build a
@@ -1951,7 +2051,7 @@ while (addr_new != NULL)
             {
             log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand list of hosts "
               "\"%s\" in %s transport for callout: %s", tf.hosts,
-              addr->transport->name, expand_string_message);
+              tp->name, expand_string_message);
             }
           else
             {
@@ -1977,18 +2077,16 @@ while (addr_new != NULL)
                 (void)host_find_byname(host, NULL, flags, NULL, TRUE);
               else
                {
-               uschar * d_request = NULL, * d_require = NULL;
-               if (Ustrcmp(addr->transport->driver_name, "smtp") == 0)
+               dnssec_domains * dnssec_domains = NULL;
+               if (Ustrcmp(tp->driver_name, "smtp") == 0)
                  {
                  smtp_transport_options_block * ob =
-                     (smtp_transport_options_block *)
-                       addr->transport->options_block;
-                 d_request = ob->dnssec_request_domains;
-                 d_require = ob->dnssec_require_domains;
+                     (smtp_transport_options_block *) tp->options_block;
+                 dnssec_domains = &ob->dnssec;
                  }
 
                 (void)host_find_bydns(host, NULL, flags, NULL, NULL, NULL,
-                 d_request, d_require, NULL, NULL);
+                 dnssec_domains, NULL, NULL);
                }
               }
             }
@@ -2169,7 +2267,7 @@ while (addr_new != NULL)
       /* If we have carried on to verify a child address, we want the value
       of $address_data to be that of the child */
 
-      vaddr->p.address_data = addr->p.address_data;
+      vaddr->prop.address_data = addr->prop.address_data;
       yield = OK;
       goto out;
       }
@@ -2192,17 +2290,18 @@ if (allok && addr_local == NULL && addr_remote == NULL)
   }
 
 for (addr_list = addr_local, i = 0; i < 2; addr_list = addr_remote, i++)
-  {
-  while (addr_list != NULL)
+  while (addr_list)
     {
     address_item *addr = addr_list;
     address_item *p = addr->parent;
+    transport_instance * tp = addr->transport;
+
     addr_list = addr->next;
 
     fprintf(f, "%s", CS addr->address);
 #ifdef EXPERIMENTAL_SRS
-    if(addr->p.srs_sender)
-      fprintf(f, "    [srs = %s]", addr->p.srs_sender);
+    if(addr->prop.srs_sender)
+      fprintf(f, "    [srs = %s]", addr->prop.srs_sender);
 #endif
 
     /* If the address is a duplicate, show something about it. */
@@ -2210,67 +2309,56 @@ for (addr_list = addr_local, i = 0; i < 2; addr_list = addr_remote, i++)
     if (!testflag(addr, af_pfr))
       {
       tree_node *tnode;
-      if ((tnode = tree_search(tree_duplicates, addr->unique)) != NULL)
+      if ((tnode = tree_search(tree_duplicates, addr->unique)))
         fprintf(f, "   [duplicate, would not be delivered]");
       else tree_add_duplicate(addr->unique, addr);
       }
 
     /* Now show its parents */
 
-    while (p != NULL)
-      {
+    for (p = addr->parent; p; p = p->parent)
       fprintf(f, "\n    <-- %s", p->address);
-      p = p->parent;
-      }
     fprintf(f, "\n  ");
 
     /* Show router, and transport */
 
-    fprintf(f, "router = %s, ", addr->router->name);
-    fprintf(f, "transport = %s\n", (addr->transport == NULL)? US"unset" :
-      addr->transport->name);
+    fprintf(f, "router = %s, transport = %s\n",
+      addr->router->name, tp ? tp->name : US"unset");
 
     /* Show any hosts that are set up by a router unless the transport
     is going to override them; fiddle a bit to get a nice format. */
 
-    if (addr->host_list != NULL && addr->transport != NULL &&
-        !addr->transport->overrides_hosts)
+    if (addr->host_list && tp && !tp->overrides_hosts)
       {
       host_item *h;
       int maxlen = 0;
       int maxaddlen = 0;
-      for (h = addr->host_list; h != NULL; h = h->next)
-        {
+      for (h = addr->host_list; h; h = h->next)
+        {                              /* get max lengths of host names, addrs */
         int len = Ustrlen(h->name);
         if (len > maxlen) maxlen = len;
-        len = (h->address != NULL)? Ustrlen(h->address) : 7;
+        len = h->address ? Ustrlen(h->address) : 7;
         if (len > maxaddlen) maxaddlen = len;
         }
-      for (h = addr->host_list; h != NULL; h = h->next)
-        {
-        int len = Ustrlen(h->name);
-        fprintf(f, "  host %s ", h->name);
-        while (len++ < maxlen) fprintf(f, " ");
-        if (h->address != NULL)
-          {
-          fprintf(f, "[%s] ", h->address);
-          len = Ustrlen(h->address);
-          }
-        else if (!addr->transport->info->local)  /* Omit [unknown] for local */
-          {
-          fprintf(f, "[unknown] ");
-          len = 7;
-          }
-        else len = -3;
-        while (len++ < maxaddlen) fprintf(f," ");
-        if (h->mx >= 0) fprintf(f, "MX=%d", h->mx);
+      for (h = addr->host_list; h; h = h->next)
+       {
+       fprintf(f, "  host %-*s ", maxlen, h->name);
+
+       if (h->address)
+         fprintf(f, "[%s%-*c", h->address, maxaddlen+1 - Ustrlen(h->address), ']');
+       else if (tp->info->local)
+         fprintf(f, " %-*s ", maxaddlen, "");  /* Omit [unknown] for local */
+       else
+         fprintf(f, "[%s%-*c", "unknown", maxaddlen+1 - 7, ']');
+
+        if (h->mx >= 0) fprintf(f, " MX=%d", h->mx);
         if (h->port != PORT_NONE) fprintf(f, " port=%d", h->port);
-        if (h->status == hstatus_unusable) fprintf(f, " ** unusable **");
-        fprintf(f, "\n");
+        if (running_in_test_harness  &&  h->dnssec == DS_YES) fputs(" AD", f);
+        if (h->status == hstatus_unusable) fputs(" ** unusable **", f);
+       fputc('\n', f);
         }
       }
     }
-  }
 
 /* Yield will be DEFER or FAIL if any one address has, only for full_info (which is
 the -bv or -bt case). */
@@ -2812,7 +2900,7 @@ if (ip_bind(sock, host_af, interface_address, 0) < 0)
 if (ip_connect(sock, host_af, sender_host_address, port, rfc1413_query_timeout)
      < 0)
   {
-  if (errno == ETIMEDOUT && (log_extra_selector & LX_ident_timeout) != 0)
+  if (errno == ETIMEDOUT && LOGGING(ident_timeout))
     {
     log_write(0, LOG_MAIN, "ident connection to %s timed out",
       sender_host_address);
@@ -3142,6 +3230,10 @@ if (*t == 0)
   h.address = NULL;
   h.mx = MX_NONE;
 
+  /* Using byname rather than bydns here means we cannot determine dnssec
+  status.  On the other hand it is unclear how that could be either
+  propagated up or enforced. */
+
   rc = host_find_byname(&h, NULL, HOST_FIND_QUALIFY_SINGLE, NULL, FALSE);
   if (rc == HOST_FOUND || rc == HOST_FOUND_LOCAL)
     {
@@ -3476,21 +3568,37 @@ if (!string_format(query, sizeof(query), "%s.%s", prepend, domain))
 
 /* Look for this query in the cache. */
 
-t = tree_search(dnsbl_cache, query);
+if (  (t = tree_search(dnsbl_cache, query))
+   && (cb = t->data.ptr)->expiry > time(NULL)
+   )
+
+/* Previous lookup was cached */
+
+  {
+  HDEBUG(D_dnsbl) debug_printf("using result of previous DNS lookup\n");
+  }
 
 /* If not cached from a previous lookup, we must do a DNS lookup, and
 cache the result in permanent memory. */
 
-if (t == NULL)
+else
   {
+  uint ttl = 3600;
+
   store_pool = POOL_PERM;
 
-  /* Set up a tree entry to cache the lookup */
+  if (t)
+    {
+    HDEBUG(D_dnsbl) debug_printf("cached data found but past valid time; ");
+    }
 
-  t = store_get(sizeof(tree_node) + Ustrlen(query));
-  Ustrcpy(t->name, query);
-  t->data.ptr = cb = store_get(sizeof(dnsbl_cache_block));
-  (void)tree_insertnode(&dnsbl_cache, t);
+  else
+    {  /* Set up a tree entry to cache the lookup */
+    t = store_get(sizeof(tree_node) + Ustrlen(query));
+    Ustrcpy(t->name, query);
+    t->data.ptr = cb = store_get(sizeof(dnsbl_cache_block));
+    (void)tree_insertnode(&dnsbl_cache, t);
+    }
 
   /* Do the DNS loopup . */
 
@@ -3508,24 +3616,28 @@ if (t == NULL)
 
   Quite apart from one A6 RR generating multiple addresses, there are DNS
   lists that return more than one A record, so we must handle multiple
-  addresses generated in that way as well. */
+  addresses generated in that way as well.
+
+  Mark the cache entry with the "now" plus the minimum of the address TTLs,
+  or some suitably far-future time if none were found. */
 
   if (cb->rc == DNS_SUCCEED)
     {
     dns_record *rr;
     dns_address **addrp = &(cb->rhs);
     for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
-         rr != NULL;
+         rr;
          rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
       {
       if (rr->type == T_A)
         {
         dns_address *da = dns_address_from_rr(&dnsa, rr);
-        if (da != NULL)
+        if (da)
           {
           *addrp = da;
           while (da->next != NULL) da = da->next;
           addrp = &(da->next);
+         if (ttl > rr->ttl) ttl = rr->ttl;
           }
         }
       }
@@ -3537,17 +3649,10 @@ if (t == NULL)
     if (cb->rhs == NULL) cb->rc = DNS_NODATA;
     }
 
+  cb->expiry = time(NULL)+ttl;
   store_pool = old_pool;
   }
 
-/* Previous lookup was cached */
-
-else
-  {
-  HDEBUG(D_dnsbl) debug_printf("using result of previous DNS lookup\n");
-  cb = t->data.ptr;
-  }
-
 /* We now have the result of the DNS lookup, either newly done, or cached
 from a previous call. If the lookup succeeded, check against the address
 list if there is one. This may be a positive equality list (introduced by