Another valgrind.h portability fix.
[exim.git] / src / src / verify.c
index 9ec8d2bcebfa2885478f6778fe2f78c03c1f0151..f653b6e0d27f8aef751d9afe04699de613f14a42 100644 (file)
@@ -1,10 +1,10 @@
-/* $Cambridge: exim/src/src/verify.c,v 1.44 2006/12/11 14:15:59 ph10 Exp $ */
+/* $Cambridge: exim/src/src/verify.c,v 1.55 2010/06/05 23:50:18 pdp Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2006 */
+/* Copyright (c) University of Cambridge 1995 - 2009 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Functions concerned with verifying things. The original code for callout
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Functions concerned with verifying things. The original code for callout
@@ -29,6 +29,12 @@ typedef struct dnsbl_cache_block {
 static tree_node *dnsbl_cache = NULL;
 
 
 static tree_node *dnsbl_cache = NULL;
 
 
+/* Bits for match_type in one_check_dnsbl() */
+
+#define MT_NOT 1
+#define MT_ALL 2
+
+
 
 /*************************************************
 *          Retrieve a callout cache record       *
 
 /*************************************************
 *          Retrieve a callout cache record       *
@@ -379,6 +385,14 @@ if (callout_overall < 0) callout_overall = 4 * callout;
 if (callout_connect < 0) callout_connect = callout;
 callout_start_time = time(NULL);
 
 if (callout_connect < 0) callout_connect = callout;
 callout_start_time = time(NULL);
 
+/* Before doing a real callout, if this is an SMTP connection, flush the SMTP
+output because a callout might take some time. When PIPELINING is active and
+there are many recipients, the total time for doing lots of callouts can add up
+and cause the client to time out. So in this case we forgo the PIPELINING
+optimization. */
+
+if (smtp_out != NULL && !disable_callout_flush) mac_smtp_fflush();
+
 /* Now make connections to the hosts and do real callouts. The list of hosts
 is passed in as an argument. */
 
 /* Now make connections to the hosts and do real callouts. The list of hosts
 is passed in as an argument. */
 
@@ -436,21 +450,6 @@ for (host = host_list; host != NULL && !done; host = host->next)
     log_write(0, LOG_MAIN|LOG_PANIC, "<%s>: %s", addr->address,
       addr->message);
 
     log_write(0, LOG_MAIN|LOG_PANIC, "<%s>: %s", addr->address,
       addr->message);
 
-  /* Expand the helo_data string to find the host name to use. */
-
-  if (tf->helo_data != NULL)
-    {
-    uschar *s = expand_string(tf->helo_data);
-    if (s == NULL)
-      log_write(0, LOG_MAIN|LOG_PANIC, "<%s>: failed to expand transport's "
-        "helo_data value for callout: %s", addr->address,
-        expand_string_message);
-    else active_hostname = s;
-    }
-
-  deliver_host = deliver_host_address = NULL;
-  deliver_domain = save_deliver_domain;
-
   /* Set HELO string according to the protocol */
 
   if (Ustrcmp(tf->protocol, "lmtp") == 0) helo = US"LHLO";
   /* Set HELO string according to the protocol */
 
   if (Ustrcmp(tf->protocol, "lmtp") == 0) helo = US"LHLO";
@@ -481,9 +480,26 @@ for (host = host_list; host != NULL && !done; host = host->next)
     {
     addr->message = string_sprintf("could not connect to %s [%s]: %s",
         host->name, host->address, strerror(errno));
     {
     addr->message = string_sprintf("could not connect to %s [%s]: %s",
         host->name, host->address, strerror(errno));
+    deliver_host = deliver_host_address = NULL;
+    deliver_domain = save_deliver_domain;
     continue;
     }
 
     continue;
     }
 
+  /* Expand the helo_data string to find the host name to use. */
+
+  if (tf->helo_data != NULL)
+    {
+    uschar *s = expand_string(tf->helo_data);
+    if (s == NULL)
+      log_write(0, LOG_MAIN|LOG_PANIC, "<%s>: failed to expand transport's "
+        "helo_data value for callout: %s", addr->address,
+        expand_string_message);
+    else active_hostname = s;
+    }
+
+  deliver_host = deliver_host_address = NULL;
+  deliver_domain = save_deliver_domain;
+
   /* Wait for initial response, and send HELO. The smtp_write_command()
   function leaves its command in big_buffer. This is used in error responses.
   Initialize it in case the connection is rejected. */
   /* Wait for initial response, and send HELO. The smtp_write_command()
   function leaves its command in big_buffer. This is used in error responses.
   Initialize it in case the connection is rejected. */
@@ -839,6 +855,7 @@ if (addr != vaddr)
   vaddr->basic_errno = addr->basic_errno;
   vaddr->more_errno = addr->more_errno;
   vaddr->p.address_data = addr->p.address_data;
   vaddr->basic_errno = addr->basic_errno;
   vaddr->more_errno = addr->more_errno;
   vaddr->p.address_data = addr->p.address_data;
+  copyflag(vaddr, addr, af_pass_message);
   }
 return yield;
 }
   }
 return yield;
 }
@@ -846,6 +863,42 @@ return yield;
 
 
 
 
 
 
+/**************************************************
+* printf that automatically handles TLS if needed *
+***************************************************/
+
+/* This function is used by verify_address() as a substitute for all fprintf()
+calls; a direct fprintf() will not produce output in a TLS SMTP session, such
+as a response to an EXPN command.  smtp_in.c makes smtp_printf available but
+that assumes that we always use the smtp_out FILE* when not using TLS or the
+ssl buffer when we are.  Instead we take a FILE* parameter and check to see if
+that is smtp_out; if so, smtp_printf() with TLS support, otherwise regular
+fprintf().
+
+Arguments:
+  f           the candidate FILE* to write to
+  format      format string
+  ...         optional arguments
+
+Returns:
+              nothing
+*/
+
+static void PRINTF_FUNCTION(2,3)
+respond_printf(FILE *f, char *format, ...)
+{
+va_list ap;
+
+va_start(ap, format);
+if (smtp_out && (f == smtp_out))
+  smtp_vprintf(format, ap);
+else
+  vfprintf(f, format, ap);
+va_end(ap);
+}
+
+
+
 /*************************************************
 *            Verify an email address             *
 *************************************************/
 /*************************************************
 *            Verify an email address             *
 *************************************************/
@@ -945,8 +998,8 @@ if (parse_find_at(address) == NULL)
   if ((options & vopt_qualify) == 0)
     {
     if (f != NULL)
   if ((options & vopt_qualify) == 0)
     {
     if (f != NULL)
-      fprintf(f, "%sA domain is required for \"%s\"%s\n", ko_prefix, address,
-        cr);
+      respond_printf(f, "%sA domain is required for \"%s\"%s\n",
+        ko_prefix, address, cr);
     *failure_ptr = US"qualify";
     return FAIL;
     }
     *failure_ptr = US"qualify";
     return FAIL;
     }
@@ -1210,24 +1263,25 @@ while (addr_new != NULL)
       {
       address_item *p = addr->parent;
 
       {
       address_item *p = addr->parent;
 
-      fprintf(f, "%s%s %s", ko_prefix, full_info? addr->address : address,
+      respond_printf(f, "%s%s %s", ko_prefix,
+        full_info? addr->address : address,
         address_test_mode? "is undeliverable" : "failed to verify");
       if (!expn && admin_user)
         {
         if (addr->basic_errno > 0)
         address_test_mode? "is undeliverable" : "failed to verify");
       if (!expn && admin_user)
         {
         if (addr->basic_errno > 0)
-          fprintf(f, ": %s", strerror(addr->basic_errno));
+          respond_printf(f, ": %s", strerror(addr->basic_errno));
         if (addr->message != NULL)
         if (addr->message != NULL)
-          fprintf(f, ": %s", addr->message);
+          respond_printf(f, ": %s", addr->message);
         }
 
       /* Show parents iff doing full info */
 
       if (full_info) while (p != NULL)
         {
         }
 
       /* Show parents iff doing full info */
 
       if (full_info) while (p != NULL)
         {
-        fprintf(f, "%s\n    <-- %s", cr, p->address);
+        respond_printf(f, "%s\n    <-- %s", cr, p->address);
         p = p->parent;
         }
         p = p->parent;
         }
-      fprintf(f, "%s\n", cr);
+      respond_printf(f, "%s\n", cr);
       }
 
     if (!full_info) return copy_error(vaddr, addr, FAIL);
       }
 
     if (!full_info) return copy_error(vaddr, addr, FAIL);
@@ -1242,28 +1296,27 @@ while (addr_new != NULL)
     if (f != NULL)
       {
       address_item *p = addr->parent;
     if (f != NULL)
       {
       address_item *p = addr->parent;
-      fprintf(f, "%s%s cannot be resolved at this time", ko_prefix,
+      respond_printf(f, "%s%s cannot be resolved at this time", ko_prefix,
         full_info? addr->address : address);
       if (!expn && admin_user)
         {
         if (addr->basic_errno > 0)
         full_info? addr->address : address);
       if (!expn && admin_user)
         {
         if (addr->basic_errno > 0)
-          fprintf(f, ": %s", strerror(addr->basic_errno));
+          respond_printf(f, ": %s", strerror(addr->basic_errno));
         if (addr->message != NULL)
         if (addr->message != NULL)
-          fprintf(f, ": %s", addr->message);
+          respond_printf(f, ": %s", addr->message);
         else if (addr->basic_errno <= 0)
         else if (addr->basic_errno <= 0)
-          fprintf(f, ": unknown error");
+          respond_printf(f, ": unknown error");
         }
 
       /* Show parents iff doing full info */
 
       if (full_info) while (p != NULL)
         {
         }
 
       /* Show parents iff doing full info */
 
       if (full_info) while (p != NULL)
         {
-        fprintf(f, "%s\n    <-- %s", cr, p->address);
+        respond_printf(f, "%s\n    <-- %s", cr, p->address);
         p = p->parent;
         }
         p = p->parent;
         }
-      fprintf(f, "%s\n", cr);
+      respond_printf(f, "%s\n", cr);
       }
       }
-
     if (!full_info) return copy_error(vaddr, addr, DEFER);
       else if (yield == OK) yield = DEFER;
     }
     if (!full_info) return copy_error(vaddr, addr, DEFER);
       else if (yield == OK) yield = DEFER;
     }
@@ -1277,16 +1330,16 @@ while (addr_new != NULL)
     if (addr_new == NULL)
       {
       if (addr_local == NULL && addr_remote == NULL)
     if (addr_new == NULL)
       {
       if (addr_local == NULL && addr_remote == NULL)
-        fprintf(f, "250 mail to <%s> is discarded\r\n", address);
+        respond_printf(f, "250 mail to <%s> is discarded\r\n", address);
       else
       else
-        fprintf(f, "250 <%s>\r\n", address);
+        respond_printf(f, "250 <%s>\r\n", address);
       }
     else while (addr_new != NULL)
       {
       address_item *addr2 = addr_new;
       addr_new = addr2->next;
       if (addr_new == NULL) ok_prefix = US"250 ";
       }
     else while (addr_new != NULL)
       {
       address_item *addr2 = addr_new;
       addr_new = addr2->next;
       if (addr_new == NULL) ok_prefix = US"250 ";
-      fprintf(f, "%s<%s>\r\n", ok_prefix, addr2->address);
+      respond_printf(f, "%s<%s>\r\n", ok_prefix, addr2->address);
       }
     return OK;
     }
       }
     return OK;
     }
@@ -2185,7 +2238,8 @@ if (iplookup)
   name, we have to fish the file off the start of the query. For a single-key
   lookup, the key is the current IP address, masked appropriately, and
   reconverted to text form, with the mask appended. For IPv6 addresses, specify
   name, we have to fish the file off the start of the query. For a single-key
   lookup, the key is the current IP address, masked appropriately, and
   reconverted to text form, with the mask appended. For IPv6 addresses, specify
-  dot separators instead of colons. */
+  dot separators instead of colons, except when the lookup type is "iplsearch".
+  */
 
   if (mac_islookup(search_type, lookup_absfilequery))
     {
 
   if (mac_islookup(search_type, lookup_absfilequery))
     {
@@ -2200,11 +2254,13 @@ if (iplookup)
     filename = NULL;
     key = semicolon + 1;
     }
     filename = NULL;
     key = semicolon + 1;
     }
-  else
+  else   /* Single-key style */
     {
     {
+    int sep = (Ustrcmp(lookup_list[search_type]->name, "iplsearch") == 0)?
+      ':' : '.';
     insize = host_aton(cb->host_address, incoming);
     host_mask(insize, incoming, mlen);
     insize = host_aton(cb->host_address, incoming);
     host_mask(insize, incoming, mlen);
-    (void)host_nmtoa(insize, incoming, mlen, buffer, '.');
+    (void)host_nmtoa(insize, incoming, mlen, buffer, sep);
     key = buffer;
     filename = semicolon + 1;
     }
     key = buffer;
     filename = semicolon + 1;
     }
@@ -2457,16 +2513,18 @@ return verify_check_this_host(listptr, sender_host_cache, NULL,
 
 
 /*************************************************
 
 
 /*************************************************
-*    Invert an IP address for a DNS black list   *
+*              Invert an IP address              *
 *************************************************/
 
 *************************************************/
 
-/*
+/* Originally just used for DNS xBL lists, now also used for the
+reverse_ip expansion operator.
+
 Arguments:
   buffer         where to put the answer
   address        the address to invert
 */
 
 Arguments:
   buffer         where to put the answer
   address        the address to invert
 */
 
-static void
+void
 invert_address(uschar *buffer, uschar *address)
 {
 int bin[4];
 invert_address(uschar *buffer, uschar *address)
 {
 int bin[4];
@@ -2540,7 +2598,12 @@ Arguments:
                    reversed if IP address)
   iplist         the list of matching IP addresses, or NULL for "any"
   bitmask        true if bitmask matching is wanted
                    reversed if IP address)
   iplist         the list of matching IP addresses, or NULL for "any"
   bitmask        true if bitmask matching is wanted
-  invert_result  true if result to be inverted
+  match_type     condition for 'succeed' result
+                   0 => Any RR in iplist     (=)
+                   1 => No RR in iplist      (!=)
+                   2 => All RRs in iplist    (==)
+                   3 => Some RRs not in iplist (!==)
+                   the two bits are defined as MT_NOT and MT_ALL
   defer_return   what to return for a defer
 
 Returns:         OK if lookup succeeded
   defer_return   what to return for a defer
 
 Returns:         OK if lookup succeeded
@@ -2549,7 +2612,7 @@ Returns:         OK if lookup succeeded
 
 static int
 one_check_dnsbl(uschar *domain, uschar *domain_txt, uschar *keydomain,
 
 static int
 one_check_dnsbl(uschar *domain, uschar *domain_txt, uschar *keydomain,
-  uschar *prepend, uschar *iplist, BOOL bitmask, BOOL invert_result,
+  uschar *prepend, uschar *iplist, BOOL bitmask, int match_type,
   int defer_return)
 {
 dns_answer dnsa;
   int defer_return)
 {
 dns_answer dnsa;
@@ -2668,21 +2731,25 @@ if (cb->rc == DNS_SUCCEED)
 
   if (iplist != NULL)
     {
 
   if (iplist != NULL)
     {
-    int ipsep = ',';
-    uschar ip[46];
-    uschar *ptr = iplist;
-
-    while (string_nextinlist(&ptr, &ipsep, ip, sizeof(ip)) != NULL)
+    for (da = cb->rhs; da != NULL; da = da->next)
       {
       {
+      int ipsep = ',';
+      uschar ip[46];
+      uschar *ptr = iplist;
+      uschar *res;
+
       /* Handle exact matching */
       /* Handle exact matching */
+
       if (!bitmask)
         {
       if (!bitmask)
         {
-        for (da = cb->rhs; da != NULL; da = da->next)
+        while ((res = string_nextinlist(&ptr, &ipsep, ip, sizeof(ip))) != NULL)
           {
           if (Ustrcmp(CS da->address, ip) == 0) break;
           }
         }
           {
           if (Ustrcmp(CS da->address, ip) == 0) break;
           }
         }
+
       /* Handle bitmask matching */
       /* Handle bitmask matching */
+
       else
         {
         int address[4];
       else
         {
         int address[4];
@@ -2695,37 +2762,60 @@ if (cb->rc == DNS_SUCCEED)
         ignore IPv6 addresses. The default mask is 0, which always matches.
         We change this only for IPv4 addresses in the list. */
 
         ignore IPv6 addresses. The default mask is 0, which always matches.
         We change this only for IPv4 addresses in the list. */
 
-        if (host_aton(ip, address) == 1) mask = address[0];
+        if (host_aton(da->address, address) == 1) mask = address[0];
 
         /* Scan the returned addresses, skipping any that are IPv6 */
 
 
         /* Scan the returned addresses, skipping any that are IPv6 */
 
-        for (da = cb->rhs; da != NULL; da = da->next)
+        while ((res = string_nextinlist(&ptr, &ipsep, ip, sizeof(ip))) != NULL)
           {
           {
-          if (host_aton(da->address, address) != 1) continue;
-          if ((address[0] & mask) == mask) break;
+          if (host_aton(ip, address) != 1) continue;
+          if ((address[0] & mask) == address[0]) break;
           }
         }
 
           }
         }
 
-      /* Break out if a match has been found */
+      /* If either
+
+         (a) An IP address in an any ('=') list matched, or
+         (b) No IP address in an all ('==') list matched
+
+      then we're done searching. */
 
 
-      if (da != NULL) break;
+      if (((match_type & MT_ALL) != 0) == (res == NULL)) break;
       }
 
       }
 
-    /* If either
+    /* If da == NULL, either
 
 
-       (a) No IP address in a positive list matched, or
-       (b) An IP address in a negative list did match
+       (a) No IP address in an any ('=') list matched, or
+       (b) An IP address in an all ('==') list didn't match
 
 
-    then behave as if the DNSBL lookup had not succeeded, i.e. the host is
-    not on the list. */
+    so behave as if the DNSBL lookup had not succeeded, i.e. the host is not on
+    the list. */
 
 
-    if (invert_result != (da == NULL))
+    if ((match_type == MT_NOT || match_type == MT_ALL) != (da == NULL))
       {
       HDEBUG(D_dnsbl)
         {
       {
       HDEBUG(D_dnsbl)
         {
+        uschar *res = NULL;
+        switch(match_type)
+          {
+          case 0:
+          res = US"was no match";
+          break;
+          case MT_NOT:
+          res = US"was an exclude match";
+          break;
+          case MT_ALL:
+          res = US"was an IP address that did not match";
+          break;
+          case MT_NOT|MT_ALL:
+          res = US"were no IP addresses that did not match";
+          break;
+          }
         debug_printf("=> but we are not accepting this block class because\n");
         debug_printf("=> but we are not accepting this block class because\n");
-        debug_printf("=> there was %s match for %c%s\n",
-          invert_result? "an exclude":"no", bitmask? '&' : '=', iplist);
+        debug_printf("=> there %s for %s%c%s\n",
+          res,
+          ((match_type & MT_ALL) == 0)? "" : "=",
+          bitmask? '&' : '=', iplist);
         }
       return FAIL;
       }
         }
       return FAIL;
       }
@@ -2739,7 +2829,7 @@ if (cb->rc == DNS_SUCCEED)
 
   if (domain_txt != domain)
     return one_check_dnsbl(domain_txt, domain_txt, keydomain, prepend, NULL,
 
   if (domain_txt != domain)
     return one_check_dnsbl(domain_txt, domain_txt, keydomain, prepend, NULL,
-      FALSE, invert_result, defer_return);
+      FALSE, match_type, defer_return);
 
   /* If there is no alternate domain, look up a TXT record in the main domain
   if it has not previously been cached. */
 
   /* If there is no alternate domain, look up a TXT record in the main domain
   if it has not previously been cached. */
@@ -2852,7 +2942,6 @@ verify_check_dnsbl(uschar **listptr)
 {
 int sep = 0;
 int defer_return = FAIL;
 {
 int sep = 0;
 int defer_return = FAIL;
-BOOL invert_result = FALSE;
 uschar *list = *listptr;
 uschar *domain;
 uschar *s;
 uschar *list = *listptr;
 uschar *domain;
 uschar *s;
@@ -2873,6 +2962,7 @@ while ((domain = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL
   {
   int rc;
   BOOL bitmask = FALSE;
   {
   int rc;
   BOOL bitmask = FALSE;
+  int match_type = 0;
   uschar *domain_txt;
   uschar *comma;
   uschar *iplist;
   uschar *domain_txt;
   uschar *comma;
   uschar *iplist;
@@ -2899,8 +2989,8 @@ while ((domain = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL
   if (key != NULL) *key++ = 0;
 
   /* See if there's a list of addresses supplied after the domain name. This is
   if (key != NULL) *key++ = 0;
 
   /* See if there's a list of addresses supplied after the domain name. This is
-  introduced by an = or a & character; if preceded by ! we invert the result.
-  */
+  introduced by an = or a & character; if preceded by = we require all matches
+  and if preceded by ! we invert the result. */
 
   iplist = Ustrchr(domain, '=');
   if (iplist == NULL)
 
   iplist = Ustrchr(domain, '=');
   if (iplist == NULL)
@@ -2909,14 +2999,23 @@ while ((domain = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL
     iplist = Ustrchr(domain, '&');
     }
 
     iplist = Ustrchr(domain, '&');
     }
 
-  if (iplist != NULL)
+  if (iplist != NULL)                          /* Found either = or & */
     {
     {
-    if (iplist > domain && iplist[-1] == '!')
+    if (iplist > domain && iplist[-1] == '!')  /* Handle preceding ! */
       {
       {
-      invert_result = TRUE;
+      match_type |= MT_NOT;
       iplist[-1] = 0;
       }
       iplist[-1] = 0;
       }
-    *iplist++ = 0;
+
+    *iplist++ = 0;                             /* Terminate domain, move on */
+
+    /* If we found = (bitmask == FALSE), check for == or =& */
+
+    if (!bitmask && (*iplist == '=' || *iplist == '&'))
+      {
+      bitmask = *iplist++ == '&';
+      match_type |= MT_ALL;
+      }
     }
 
   /* If there is a comma in the domain, it indicates that a second domain for
     }
 
   /* If there is a comma in the domain, it indicates that a second domain for
@@ -2939,7 +3038,7 @@ while ((domain = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL
 
   for (s = domain; *s != 0; s++)
     {
 
   for (s = domain; *s != 0; s++)
     {
-    if (!isalnum(*s) && *s != '-' && *s != '.')
+    if (!isalnum(*s) && *s != '-' && *s != '.' && *s != '_')
       {
       log_write(0, LOG_MAIN, "dnslists domain \"%s\" contains "
         "strange characters - is this right?", domain);
       {
       log_write(0, LOG_MAIN, "dnslists domain \"%s\" contains "
         "strange characters - is this right?", domain);
@@ -2951,7 +3050,7 @@ while ((domain = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL
 
   if (domain_txt != domain) for (s = domain_txt; *s != 0; s++)
     {
 
   if (domain_txt != domain) for (s = domain_txt; *s != 0; s++)
     {
-    if (!isalnum(*s) && *s != '-' && *s != '.')
+    if (!isalnum(*s) && *s != '-' && *s != '.' && *s != '_')
       {
       log_write(0, LOG_MAIN, "dnslists domain \"%s\" contains "
         "strange characters - is this right?", domain_txt);
       {
       log_write(0, LOG_MAIN, "dnslists domain \"%s\" contains "
         "strange characters - is this right?", domain_txt);
@@ -2967,10 +3066,11 @@ while ((domain = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL
     if (sender_host_address == NULL) return FAIL;    /* can never match */
     if (revadd[0] == 0) invert_address(revadd, sender_host_address);
     rc = one_check_dnsbl(domain, domain_txt, sender_host_address, revadd,
     if (sender_host_address == NULL) return FAIL;    /* can never match */
     if (revadd[0] == 0) invert_address(revadd, sender_host_address);
     rc = one_check_dnsbl(domain, domain_txt, sender_host_address, revadd,
-      iplist, bitmask, invert_result, defer_return);
+      iplist, bitmask, match_type, defer_return);
     if (rc == OK)
       {
       dnslist_domain = string_copy(domain_txt);
     if (rc == OK)
       {
       dnslist_domain = string_copy(domain_txt);
+      dnslist_matched = string_copy(sender_host_address);
       HDEBUG(D_dnsbl) debug_printf("=> that means %s is listed at %s\n",
         sender_host_address, dnslist_domain);
       }
       HDEBUG(D_dnsbl) debug_printf("=> that means %s is listed at %s\n",
         sender_host_address, dnslist_domain);
       }
@@ -3000,11 +3100,12 @@ while ((domain = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL
         }
 
       rc = one_check_dnsbl(domain, domain_txt, keydomain, prepend, iplist,
         }
 
       rc = one_check_dnsbl(domain, domain_txt, keydomain, prepend, iplist,
-        bitmask, invert_result, defer_return);
+        bitmask, match_type, defer_return);
 
       if (rc == OK)
         {
         dnslist_domain = string_copy(domain_txt);
 
       if (rc == OK)
         {
         dnslist_domain = string_copy(domain_txt);
+        dnslist_matched = string_copy(keydomain);
         HDEBUG(D_dnsbl) debug_printf("=> that means %s is listed at %s\n",
           keydomain, dnslist_domain);
         return OK;
         HDEBUG(D_dnsbl) debug_printf("=> that means %s is listed at %s\n",
           keydomain, dnslist_domain);
         return OK;