Patch imported from bugzilla 1031. Axel Rau.
authorJeremy Harris <jgh146exb@wizmail.org>
Sun, 30 Jun 2013 15:17:55 +0000 (16:17 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Sun, 30 Jun 2013 15:17:55 +0000 (16:17 +0100)
doc/doc-txt/experimental-spec.txt
src/src/EDITME
src/src/config.h.defaults
src/src/deliver.c
src/src/exim.c
src/src/expand.c
src/src/globals.c
src/src/globals.h
src/src/readconf.c
src/src/transports/smtp.c
src/src/transports/smtp.h

index 5dd6832b1f6382cc71aa32f4f0736e99d5a161e8..047440611d0047c1436009393cc77b46f28f9533 100644 (file)
@@ -574,6 +574,85 @@ to tell the DCC routines add more information; eg, you might set
 this to some results from ClamAV.  Be careful.  Header syntax is
 not checked and is added "as is".
 
 this to some results from ClamAV.  Be careful.  Header syntax is
 not checked and is added "as is".
 
+DBL (Database Logging)
+--------------------------------------------------------------
+
+This feature allows to write exim internal log information
+(not available otherwise) into a database. 
+Initially implemented is logging of details about successfully
+completed remote deliveries, which are needed for reputation
+systems, and deferrals caused by a host error.
+
+In order to use DBL, you must set
+
+EXPERIMENTAL_DBL=yes
+
+in your Local/Makefile
+
+and define the database queries in the runtime config file, to
+be executed at end of delivery.
+
+Additionally, there are 8 more variables, available at end of
+delivery:
+
+dbl_delivery_ip             IP of host, which has accepted delivery
+dbl_delivery_port           Port of remote host which has accepted delivery
+dbl_delivery_fqdn           FQDN of host, which has accepted delivery
+dbl_delivery_local_part     local part of address being delivered
+dbl_delivery_domain         domain part of address being delivered
+dbl_delivery_confirmation   SMTP confirmation message
+
+In case of a deferral caused by a host-error:
+dbl_defer_errno             Error number
+dbl_defer_errstr            Error string possibly containing more details
+
+
+To log successful deliveries, set the following option in the main
+option part of runtime config.
+
+dbl_delivery_query
+
+An example might look like:
+
+dbl_delivery_query = \
+${lookup pgsql {SELECT * FROM record_Delivery( \
+    '${quote_pgsql:$sender_address_domain}',\
+    '${quote_pgsql:${lc:$sender_address_local_part}}', \
+    '${quote_pgsql:$dbl_delivery_domain}', \
+    '${quote_pgsql:${lc:$dbl_delivery_local_part}}', \
+    '${quote_pgsql:$dbl_delivery_ip}', \
+    '${quote_pgsql:${lc:$dbl_delivery_fqdn}}', \
+    '${quote_pgsql:$message_exim_id}')}}
+
+
+In order to log host deferrals, add the following option to an SMTP
+transport:
+
+dbl_host_defer_query
+
+This is a private option of the SMTP transport. It is intended to
+log failures of remote hosts. It is executed only when exim has
+attempted to deliver a message to a remote host and failed due to
+an error which doesn't seem to be related to the individual
+message, sender, or recipient address.
+See section 45.2 of the exim documentation for more details on how
+this is determined.
+
+Example:
+
+dbl_host_defer_query = \
+${lookup mysql {insert into delivlog set \
+    msgid = '${quote_mysql:$message_exim_id}', \
+    senderlp = '${quote_mysql:${lc:$sender_address_local_part}}', \
+    senderdom = '${quote_mysql:$sender_address_domain}', \
+    delivlp = '${quote_mysql:${lc:$dbl_delivery_local_part}}', \
+    delivdom = '${quote_mysql:$dbl_delivery_domain}', \
+    delivip = '${quote_mysql:$dbl_delivery_ip}', \
+    delivport = '${quote_mysql:$dbl_delivery_port}', \
+    delivfqdn = '${quote_mysql:$dbl_delivery_fqdn}', \
+    deliverrno = '${quote_mysql:$dbl_defer_errno}', \
+    deliverrstr = '${quote_mysql:$dbl_defer_errstr}' \
+    }}
 
 --------------------------------------------------------------
 End of file
 
 --------------------------------------------------------------
 End of file
index 95857c707ea163b9667d0e6cb0c03f4c1825fde2..1387b980aa2ea278538da5a112f7312af3fa9030 100644 (file)
@@ -452,7 +452,9 @@ EXIM_MONITOR=eximon.bin
 
 # EXPERIMENTAL_OCSP=yes
 
 
 # EXPERIMENTAL_OCSP=yes
 
-
+# This feature allows to write log information about a completed
+#  delivery into a database
+# EXPERIMENTAL_DBL=yes
 
 ###############################################################################
 #                 THESE ARE THINGS YOU MIGHT WANT TO SPECIFY                  #
 
 ###############################################################################
 #                 THESE ARE THINGS YOU MIGHT WANT TO SPECIFY                  #
index 92a4cd348373f9deb014704bb882f01eaa459ead..1652c784254178a8ae7f46a9a730412f542563b1 100644 (file)
@@ -166,6 +166,7 @@ it's a default value. */
 #define EXPERIMENTAL_OCSP
 #define EXPERIMENTAL_SPF
 #define EXPERIMENTAL_SRS
 #define EXPERIMENTAL_OCSP
 #define EXPERIMENTAL_SPF
 #define EXPERIMENTAL_SRS
+#define EXPERIMENTAL_DBL
 
 /* For developers */
 #define WANT_DEEPER_PRINTF_CHECKS
 
 /* For developers */
 #define WANT_DEEPER_PRINTF_CHECKS
index d4ea2d868c2d45916a1048985c982f432b9107d6..1c3c4bafd392b002789fa57d625e0d2c8c4845e5 100644 (file)
@@ -885,6 +885,9 @@ if (result == OK)
   if(addr->p.srs_sender)
     s = string_append(s, &size, &ptr, 3, US" SRS=<", addr->p.srs_sender, US">");
   #endif
   if(addr->p.srs_sender)
     s = string_append(s, &size, &ptr, 3, US" SRS=<", addr->p.srs_sender, US">");
   #endif
+  #ifdef EXPERIMENTAL_DBL
+  dbl_delivery_ip = NULL;      /* presume no successful remote delivery */
+  #endif
 
   /* You might think that the return path must always be set for a successful
   delivery; indeed, I did for some time, until this statement crashed. The case
 
   /* You might think that the return path must always be set for a successful
   delivery; indeed, I did for some time, until this statement crashed. The case
@@ -930,8 +933,15 @@ if (result == OK)
           addr->host_used->port));
       if (continue_sequence > 1)
         s = string_cat(s, &size, &ptr, US"*", 1);
           addr->host_used->port));
       if (continue_sequence > 1)
         s = string_cat(s, &size, &ptr, US"*", 1);
+      #ifdef EXPERIMENTAL_DBL
+      dbl_delivery_ip = string_copy(addr->host_used->address);
+      dbl_delivery_port = addr->host_used->port;
+      dbl_delivery_fqdn = string_copy(addr->host_used->name);
+      dbl_delivery_local_part = string_copy(addr->local_part);
+      dbl_delivery_domain = string_copy(addr->domain);
+      dbl_delivery_confirmation = string_copy(addr->message);
+      #endif
       }
       }
-
     #ifdef SUPPORT_TLS
     if ((log_extra_selector & LX_tls_cipher) != 0 && addr->cipher != NULL)
       s = string_append(s, &size, &ptr, 2, US" X=", addr->cipher);
     #ifdef SUPPORT_TLS
     if ((log_extra_selector & LX_tls_cipher) != 0 && addr->cipher != NULL)
       s = string_append(s, &size, &ptr, 2, US" X=", addr->cipher);
@@ -981,6 +991,14 @@ if (result == OK)
 
   s[ptr] = 0;
   log_write(0, LOG_MAIN, "%s", s);
 
   s[ptr] = 0;
   log_write(0, LOG_MAIN, "%s", s);
+  #ifdef EXPERIMENTAL_DBL
+  DEBUG(D_deliver)
+    {
+    debug_printf("  DBL(Delivery): dbl_delivery_query=|%s| dbl_delivery_IP=%s\n", dbl_delivery_query, dbl_delivery_ip);
+       }
+  if (dbl_delivery_ip != NULL && dbl_delivery_query != NULL)
+       expand_string(dbl_delivery_query);
+  #endif
   store_reset(reset_point);
   }
 
   store_reset(reset_point);
   }
 
index 76355afcc7bc9d6c6bfcf798c8462cce12cce13c..587e136856693f36012e6a0246f114765194b9a9 100644 (file)
@@ -806,6 +806,9 @@ fprintf(f, "Support for:");
 #ifdef EXPERIMENTAL_DCC
   fprintf(f, " Experimental_DCC");
 #endif
 #ifdef EXPERIMENTAL_DCC
   fprintf(f, " Experimental_DCC");
 #endif
+#ifdef EXPERIMENTAL_DBL
+  fprintf(f, " EXPERIMENTAL_DBL");
+#endif
 fprintf(f, "\n");
 
 fprintf(f, "Lookups (built-in):");
 fprintf(f, "\n");
 
 fprintf(f, "Lookups (built-in):");
index 84167b688d60c756ac0eac726622e7c7c99963b8..31d51d79ea9a59de7627861a157ef69c7b84977e 100644 (file)
@@ -410,6 +410,16 @@ static var_entry var_table[] = {
   { "compile_date",        vtype_stringptr,   &version_date },
   { "compile_number",      vtype_stringptr,   &version_cnumber },
   { "csa_status",          vtype_stringptr,   &csa_status },
   { "compile_date",        vtype_stringptr,   &version_date },
   { "compile_number",      vtype_stringptr,   &version_cnumber },
   { "csa_status",          vtype_stringptr,   &csa_status },
+#ifdef EXPERIMENTAL_DBL
+  { "dbl_defer_errno",     vtype_int,         &dbl_defer_errno },
+  { "dbl_defer_errstr",    vtype_stringptr,   &dbl_defer_errstr },
+  { "dbl_delivery_confirmation", vtype_stringptr,   &dbl_delivery_confirmation },
+  { "dbl_delivery_domain", vtype_stringptr,   &dbl_delivery_domain },
+  { "dbl_delivery_fqdn",   vtype_stringptr,   &dbl_delivery_fqdn },
+  { "dbl_delivery_ip",     vtype_stringptr,   &dbl_delivery_ip },
+  { "dbl_delivery_local_part",vtype_stringptr,&dbl_delivery_local_part },
+  { "dbl_delivery_port",   vtype_int,         &dbl_delivery_port },
+#endif
 #ifdef EXPERIMENTAL_DCC
   { "dcc_header",          vtype_stringptr,   &dcc_header },
   { "dcc_result",          vtype_stringptr,   &dcc_result },
 #ifdef EXPERIMENTAL_DCC
   { "dcc_header",          vtype_stringptr,   &dcc_header },
   { "dcc_result",          vtype_stringptr,   &dcc_result },
index f29fb3c49cddd9eab46546c0a1ec292725c59fb4..47f78e9dc00f87364087b20cc6e95f03c2df7d0e 100644 (file)
@@ -435,6 +435,18 @@ uschar *daemon_smtp_port       = US"smtp";
 int     daemon_startup_retries = 9;
 int     daemon_startup_sleep   = 30;
 
 int     daemon_startup_retries = 9;
 int     daemon_startup_sleep   = 30;
 
+#ifdef EXPERIMENTAL_DBL
+int     dbl_defer_errno        = 0;
+uschar *dbl_defer_errstr       = NULL;
+uschar *dbl_delivery_query     = NULL;
+uschar *dbl_delivery_ip        = NULL;
+int     dbl_delivery_port      = 0;
+uschar *dbl_delivery_fqdn      = NULL;
+uschar *dbl_delivery_local_part= NULL;
+uschar *dbl_delivery_domain    = NULL;
+uschar *dbl_delivery_confirmation = NULL;
+#endif
+
 #ifdef EXPERIMENTAL_DCC
 BOOL    dcc_direct_add_header  = FALSE;
 uschar *dcc_header             = NULL;
 #ifdef EXPERIMENTAL_DCC
 BOOL    dcc_direct_add_header  = FALSE;
 uschar *dcc_header             = NULL;
index fbbec3230bb8efde8b236b65899d162ef6737fd8..2e1ed46184a74e794e476fa90d4a1b1f24567870 100644 (file)
@@ -265,6 +265,18 @@ extern uschar *dccifd_address;         /* address of the dccifd daemon */
 extern uschar *dccifd_options;         /* options for the dccifd daemon */
 #endif
 
 extern uschar *dccifd_options;         /* options for the dccifd daemon */
 #endif
 
+#ifdef EXPERIMENTAL_DBL
+extern int     dbl_defer_errno;        /* error number set when a remote delivery is deferred with a host error */
+extern uschar *dbl_defer_errstr;       /* error string set when a remote delivery is deferred with a host error */
+extern uschar *dbl_delivery_query;     /* query string to log delivery info in DB */
+extern uschar *dbl_delivery_ip;        /* IP of host, which has accepted delivery */
+extern int     dbl_delivery_port;       /* port of host, which has accepted delivery */
+extern uschar *dbl_delivery_fqdn;      /* FQDN of host, which has accepted delivery */
+extern uschar *dbl_delivery_local_part;/* local part of address being delivered */
+extern uschar *dbl_delivery_domain;    /* domain part of address being delivered */
+extern uschar *dbl_delivery_confirmation; /* SMTP confirmation message */
+#endif
+
 extern BOOL    debug_daemon;           /* Debug the daemon process only */
 extern int     debug_fd;               /* The fd for debug_file */
 extern FILE   *debug_file;             /* Where to write debugging info */
 extern BOOL    debug_daemon;           /* Debug the daemon process only */
 extern int     debug_fd;               /* The fd for debug_file */
 extern FILE   *debug_file;             /* Where to write debugging info */
index c3ffe4f824625c7cb853f5f433dc539f1be4dcdf..a0c5ca0cdd0d63b2898c9a684679a385f8881774 100644 (file)
@@ -192,6 +192,9 @@ static optionlist optionlist_config[] = {
   { "daemon_smtp_ports",        opt_stringptr,   &daemon_smtp_port },
   { "daemon_startup_retries",   opt_int,         &daemon_startup_retries },
   { "daemon_startup_sleep",     opt_time,        &daemon_startup_sleep },
   { "daemon_smtp_ports",        opt_stringptr,   &daemon_smtp_port },
   { "daemon_startup_retries",   opt_int,         &daemon_startup_retries },
   { "daemon_startup_sleep",     opt_time,        &daemon_startup_sleep },
+#ifdef EXPERIMENTAL_DBL
+  { "dbl_delivery_query",       opt_stringptr,   &dbl_delivery_query },
+#endif
 #ifdef EXPERIMENTAL_DCC
   { "dcc_direct_add_header",    opt_bool,        &dcc_direct_add_header },
   { "dccifd_address",           opt_stringptr,   &dccifd_address },
 #ifdef EXPERIMENTAL_DCC
   { "dcc_direct_add_header",    opt_bool,        &dcc_direct_add_header },
   { "dccifd_address",           opt_stringptr,   &dccifd_address },
index f9f225fca341fa84afffc914e9acee62823c988a..814a63085b3ce5c50fbc6fc959671f7c8ebd4245 100644 (file)
@@ -35,6 +35,10 @@ optionlist smtp_transport_options[] = {
       (void *)offsetof(transport_instance, connection_max_messages) },
   { "data_timeout",         opt_time,
       (void *)offsetof(smtp_transport_options_block, data_timeout) },
       (void *)offsetof(transport_instance, connection_max_messages) },
   { "data_timeout",         opt_time,
       (void *)offsetof(smtp_transport_options_block, data_timeout) },
+#ifdef EXPERIMENTAL_DBL
+  { "dbl_host_defer_query",      opt_stringptr,
+         (void *)offsetof(smtp_transport_options_block, dbl_host_defer_query) },
+#endif
   { "delay_after_cutoff", opt_bool,
       (void *)offsetof(smtp_transport_options_block, delay_after_cutoff) },
 #ifndef DISABLE_DKIM
   { "delay_after_cutoff", opt_bool,
       (void *)offsetof(smtp_transport_options_block, delay_after_cutoff) },
 #ifndef DISABLE_DKIM
@@ -207,6 +211,9 @@ smtp_transport_options_block smtp_transport_option_defaults = {
   NULL,                /* dkim_sign_headers */
   NULL                 /* dkim_strict */
 #endif
   NULL,                /* dkim_sign_headers */
   NULL                 /* dkim_strict */
 #endif
+#ifdef EXPERIMENTAL_DBL
+ ,NULL                 /* dbl_host_defer_query */
+#endif
 };
 
 
 };
 
 
@@ -551,6 +558,52 @@ else
 
 
 
 
 
 
+#ifdef EXPERIMENTAL_DBL
+/*************************************************
+*          Write error message to database log   *
+*************************************************/
+
+/* This writes to the database log
+
+Arguments:
+  dbl_host_defer_query  dbl_host_defer_query from the transport options block
+  addr                  the address item containing error information
+  host                  the current host
+
+Returns:   nothing
+*/
+
+static void
+dbl_write_defer_log(uschar *dbl_host_defer_query, address_item *addr, host_item *host)
+{
+if (dbl_host_defer_query == NULL)
+       return;
+
+dbl_delivery_ip = string_copy(host->address);
+dbl_delivery_port = (host->port == PORT_NONE)? 25 : host->port;
+dbl_delivery_fqdn = string_copy(host->name);
+dbl_delivery_local_part = string_copy(addr->local_part);
+dbl_delivery_domain = string_copy(addr->domain);
+dbl_defer_errno = addr->basic_errno;
+
+dbl_defer_errstr = NULL;
+if (addr->message != NULL)
+  if (addr->basic_errno > 0)
+    dbl_defer_errstr = string_sprintf("%s: %s", addr->message, strerror(addr->basic_errno));
+  else
+       dbl_defer_errstr = string_copy(addr->message);
+else if (addr->basic_errno > 0)
+  dbl_defer_errstr = string_copy(strerror(addr->basic_errno));
+
+DEBUG(D_transport) {
+       debug_printf("  DBL(host defer): dbl_host_defer_query=|%s| dbl_delivery_IP=%s\n", dbl_host_defer_query, dbl_delivery_ip);
+}
+expand_string(dbl_host_defer_query);
+}
+#endif
+
+
+
 /*************************************************
 *           Synchronize SMTP responses           *
 *************************************************/
 /*************************************************
 *           Synchronize SMTP responses           *
 *************************************************/
@@ -1733,7 +1786,12 @@ if (!ok) ok = TRUE; else
 
     /* Set up confirmation if needed - applies only to SMTP */
 
 
     /* Set up confirmation if needed - applies only to SMTP */
 
-    if ((log_extra_selector & LX_smtp_confirmation) != 0 && !lmtp)
+    if (
+               #ifndef EXPERIMENTAL_DBL
+                       (log_extra_selector & LX_smtp_confirmation) != 0 &&
+               #endif
+                       !lmtp
+        )
       {
       uschar *s = string_printing(buffer);
       conf = (s == buffer)? (uschar *)string_copy(s) : s;
       {
       uschar *s = string_printing(buffer);
       conf = (s == buffer)? (uschar *)string_copy(s) : s;
@@ -2812,6 +2870,11 @@ for (cutoff_retry = 0; expired &&
                          first_addr->basic_errno != ERRNO_TLSFAILURE)
         write_logs(first_addr, host);
 
                          first_addr->basic_errno != ERRNO_TLSFAILURE)
         write_logs(first_addr, host);
 
+      #ifdef EXPERIMENTAL_DBL
+      if (rc == DEFER)
+        dbl_write_defer_log(ob->dbl_host_defer_query, first_addr, host);
+      #endif
+
       /* If STARTTLS was accepted, but there was a failure in setting up the
       TLS session (usually a certificate screwup), and the host is not in
       hosts_require_tls, and tls_tempfail_tryclear is true, try again, with
       /* If STARTTLS was accepted, but there was a failure in setting up the
       TLS session (usually a certificate screwup), and the host is not in
       hosts_require_tls, and tls_tempfail_tryclear is true, try again, with
@@ -2834,6 +2897,10 @@ for (cutoff_retry = 0; expired &&
           expanded_hosts != NULL, &message_defer, TRUE);
         if (rc == DEFER && first_addr->basic_errno != ERRNO_AUTHFAIL)
           write_logs(first_addr, host);
           expanded_hosts != NULL, &message_defer, TRUE);
         if (rc == DEFER && first_addr->basic_errno != ERRNO_AUTHFAIL)
           write_logs(first_addr, host);
+        #ifdef EXPERIMENTAL_DBL
+        if (rc == DEFER)
+          dbl_write_defer_log(ob->dbl_host_defer_query, first_addr, host);
+        #endif
         }
       #endif
       }
         }
       #endif
       }
index 621cb6ba9ee451c83f23024a4ec6196db897ac46..1f23d39c8abcaa549688622b0c1b559a500a0a1e 100644 (file)
@@ -64,6 +64,9 @@ typedef struct {
   uschar *dkim_sign_headers;
   uschar *dkim_strict;
   #endif
   uschar *dkim_sign_headers;
   uschar *dkim_strict;
   #endif
+  #ifdef EXPERIMENTAL_DBL
+  uschar *dbl_host_defer_query;
+  #endif
 } smtp_transport_options_block;
 
 /* Data for reading the private options. */
 } smtp_transport_options_block;
 
 /* Data for reading the private options. */