SpamAssassin: replace "backup" option on server spec with "pri=<N>". Bug 670
authorJeremy Harris <jgh146exb@wizmail.org>
Sun, 15 Feb 2015 16:50:27 +0000 (16:50 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Sun, 15 Feb 2015 16:50:27 +0000 (16:50 +0000)
doc/doc-docbook/spec.xfpt
doc/doc-txt/ChangeLog
src/src/spam.c
src/src/spam.h
test/confs/4009
test/log/4009
test/scripts/4000-scanning/4009
test/stdout/4009

index a112ec7..411eb98 100644 (file)
@@ -30829,20 +30829,29 @@ Elements after the first for Unix sockets, or second for TCP socket,
 are options.
 The supported option are:
 .code
-variant=rspamd      Use Rspamd rather than SpamAssassin protocol
+pri=<priority>      Selection priority
+weight=<value>      Selection bias
 time=<start>-<end>  Use only between these times of day
+retry=<timespec>    Retry on connect fail
 tmo=<timespec>      Connection time limit
-weight=<value>      Selection bias
-backup              Use only if all non-backup servers fail
-retry=<timespec>       Retry on connect fail
+variant=rspamd      Use Rspamd rather than SpamAssassin protocol
 .endd
 
+The &`pri`& option specifies a priority for the server within the list,
+higher values being tried first.
+The deafult priority is 1.
+
+The &`weight`& option specifies a selection bias.
+Within a priority set
+servers are queried in a random fashion, weighted by this value.
+The default value for selection bias is 1.
+
 Time specifications for the &`time`& option are <hour>.<minute>.<second>
 in the local time zone; each element being one or more digits.
 Either the seconds or both minutes and seconds, plus the leading &`.`&
 characters, may be omitted and will be taken as zero.
 
-Timeout specifications for the &`tmo`& and &`retry`& options
+Timeout specifications for the &`retry`& and &`tmo`& options
 are the usual Exim time interval standard, eg. &`20s`& or &`1m`&.
 
 The &`tmo`& option specifies an overall timeout for communication.
@@ -30851,9 +30860,6 @@ The default value is two minutes.
 The &`retry`& option specifies a time after which a single retry for
 a failed connect is made.
 The default is to not retry.
-
-Servers are queried in a random fashion, weighted by the selection bias.
-The default value for selection bias is 1.
 .wen
 
 The &%spamd_address%& variable is expanded before use if it starts with
index 0548674..cff7f44 100644 (file)
@@ -54,7 +54,7 @@ JH/14 Bug 1573: The spam= ACL condition now additionally supports Rspamd.
       Patch from Andrew Lewis.
 
 JH/15 Bug 670: The spamd_address main option (for the spam= ACL condition)
-      now supports optional time-restrictions, weighting, and backup-only
+      now supports optional time-restrictions, weighting, and priority
       modifiers per server.  Patch originally by <rommer@active.by>.
 
 JH/16 The spamd_address main option now supports a mixed list of local
index 4b99aca..05a51f6 100644 (file)
@@ -27,12 +27,12 @@ static const uschar * loglabel = US"spam acl condition:";
 static int
 spamd_param_init(spamd_address_container *spamd)
 {
-/* default spamd server weight, time and backup value */
+/* default spamd server weight, time and priority value */
 spamd->is_failed = FALSE;
-spamd->is_backup = FALSE;
 spamd->weight = SPAMD_WEIGHT;
 spamd->timeout = SPAMD_TIMEOUT;
 spamd->retry = 0;
+spamd->priority = 1;
 return 0;
 }
 
@@ -44,16 +44,11 @@ static int timesinceday = -1;
 const uschar * s;
 const uschar * name;
 
-/* check backup parameter */
-if (Ustrcmp(param, "backup") == 0)
-  {
-  spamd->is_backup = TRUE;
-  return 0; /* OK */
-  }
-
 /*XXX more clever parsing could discard embedded spaces? */
 
-/* check weight parameter */
+if (sscanf(param, "pri=%u", &spamd->priority))
+  return 0; /* OK */
+
 if (sscanf(param, "weight=%u", &spamd->weight))
   {
   if (spamd->weight == 0) /* this server disabled: skip it */
@@ -61,7 +56,6 @@ if (sscanf(param, "weight=%u", &spamd->weight))
   return 0; /* OK */
   }
 
-/* check time parameter */
 if (Ustrncmp(param, "time=", 5) == 0)
   {
   unsigned int start_h = 0, start_m = 0, start_s = 0;
@@ -136,46 +130,50 @@ badval:
 
 
 static int
-spamd_get_server(spamd_address_container **spamds, int num_servers)
+spamd_get_server(spamd_address_container ** spamds, int num_servers)
 {
 unsigned int i;
-long rnd, weights = 0;
-static BOOL srandomed = 0;
-BOOL usebackup = FALSE;
-
-for (;;)
-  {
-  /* seedup, if we have only 1 server */
-  if (num_servers == 1)
-    return (spamds[0]->is_failed ? -1 : 0);
+spamd_address_container * sd;
+long rnd, weights;
+unsigned pri;
+static BOOL srandomed = FALSE;
 
-  /* init ranmod */
-  if (!srandomed)
-    {
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-    srandom((unsigned int)(tv.tv_usec/1000));
-    srandomed = TRUE;
-    }
+/* seedup, if we have only 1 server */
+if (num_servers == 1)
+  return (spamds[0]->is_failed ? -1 : 0);
 
-  /* get sum of all weights */
-  for (i = 0; i < num_servers; i++)
-    if (!spamds[i]->is_failed && spamds[i]->is_backup == usebackup)
-      weights += spamds[i]->weight;
+/* init ranmod */
+if (!srandomed)
+  {
+  struct timeval tv;
+  gettimeofday(&tv, NULL);
+  srandom((unsigned int)(tv.tv_usec/1000));
+  srandomed = TRUE;
+  }
 
-  if (weights != 0)
-    break;
-  if (usebackup)       /* all servers failed (backups too) */
-    return -1;
-  usebackup = TRUE;
+/* scan for highest pri */
+for (pri = 0, i = 0; i < num_servers; i++)
+  {
+  sd = spamds[i];
+  if (!sd->is_failed && sd->priority > pri) pri = sd->priority;
   }
 
-rnd = random() % weights;
+/* get sum of weights */
+for (weights = 0, i = 0; i < num_servers; i++)
+  {
+  sd = spamds[i];
+  if (!sd->is_failed && sd->priority == pri) weights += sd->weight;
+  }
+if (weights == 0)      /* all servers failed */
+  return -1;
 
-for (i = 0; i < num_servers; i++)
-  if (!spamds[i]->is_failed && spamds[i]->is_backup == usebackup)
-    if ((rnd -= spamds[i]->weight) < 0)
+for (rnd = random() % weights, i = 0; i < num_servers; i++)
+  {
+  sd = spamds[i];
+  if (!sd->is_failed && sd->priority == pri)
+    if ((rnd -= sd->weight) <= 0)
       return i;
+  }
 
 log_write(0, LOG_MAIN|LOG_PANIC,
   "%s unknown error (memory/cpu corruption?)", loglabel);
@@ -251,7 +249,7 @@ if (*spamd_address == '$')
 else
   spamd_address_work = spamd_address;
 
-HDEBUG(D_acl) debug_printf("spamd: addrlist '%s'\n", spamd_address_work);
+DEBUG(D_acl) debug_printf("spamd: addrlist '%s'\n", spamd_address_work);
 
 /* check if previous spamd_address was expanded and has changed. dump cached results if so */
 if (  spam_ok
@@ -280,12 +278,13 @@ start = time(NULL);
   {
   int num_servers = 0;
   int current_server;
-  uschar *address;
-  const uschar *spamd_address_list_ptr = spamd_address_work;
+  uschar * address;
+  const uschar * spamd_address_list_ptr = spamd_address_work;
   spamd_address_container * spamd_address_vector[32];
 
   /* Check how many spamd servers we have
      and register their addresses */
+  sep = 0;                             /* default colon-sep */
   while ((address = string_nextinlist(&spamd_address_list_ptr, &sep,
                                      NULL, 0)) != NULL)
     {
@@ -294,7 +293,7 @@ start = time(NULL);
     unsigned args;
     uschar * s;
 
-    HDEBUG(D_acl) debug_printf("spamd: addr entry '%s'\n", address);
+    DEBUG(D_acl) debug_printf("spamd: addr entry '%s'\n", address);
     sd = (spamd_address_container *)store_get(sizeof(spamd_address_container));
 
     for (sublist = address, args = 0, spamd_param_init(sd);
@@ -302,7 +301,7 @@ start = time(NULL);
         args++
         )
       {
-       HDEBUG(D_acl) debug_printf("spamd:  addr parm '%s'\n", s);
+       DEBUG(D_acl) debug_printf("spamd:  addr parm '%s'\n", s);
        switch (args)
        {
        case 0:   sd->hostspec = s;
index 0e3acfc..e7da49b 100644 (file)
@@ -28,10 +28,10 @@ typedef struct spamd_address_container
   uschar * hostspec;
   int is_rspamd:1;
   int is_failed:1;
-  int is_backup:1;
   unsigned int weight;
   unsigned int timeout;
   unsigned int retry;
+  unsigned int priority;
 } spamd_address_container;
 
 #endif
index 573aa6a..2799575 100644 (file)
@@ -1,7 +1,7 @@
 # Exim test configuration 4009
 # Content-scan: spamassassin interface
 
-OPT=
+OPT= 127.0.0.1 7833
 
 exim_path = EXIM_PATH
 host_lookup_order = bydns
@@ -12,7 +12,7 @@ gecos_pattern = ""
 gecos_name = CALLER_NAME
 log_selector = +subject
 
-spamd_address = 127.0.0.1 7833 OPT
+spamd_address = OPT
 
 # ----- Main settings -----
 
index 4522ddb..612744e 100644 (file)
@@ -10,3 +10,8 @@
 1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss
 1999-03-02 09:44:33 10HmaZ-0005vi-00 => :blackhole: <userx@test.ex> R=r
 1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbA-0005vi-00 spam acl condition: spamd: failed to connect to any address for ::1: Connection refused
+1999-03-02 09:44:33 10HmbA-0005vi-00 U=CALLER Warning: no action Spam detection software, running on the system "demo",\n has NOT identified this incoming email as spam.  The original\n message has been attached to this so you can view it or label\n similar future email.  If you have any questions, see\n @@CONTACT_ADDRESS@@ for details.\n \n Content preview:  test [...]\n \n Content analysis details:   (4.5 points, 5.0 required)\n \n  pts rule name              description\n ---- ---------------------- --------------------------------------------------\n -1.0 ALL_TRUSTED            Passed through trusted hosts only via SMTP\n  1.2 MISSING_HEADERS        Missing To: header\n  1.0 MISSING_FROM           Missing From: header\n  1.8 MISSING_SUBJECT        Missing Subject: header\n  1.4 MISSING_DATE           Missing Date: header\n  0.1 MISSING_MID            Missing Message-Id: header
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss
+1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: <userx@test.ex> R=r
+1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
index 4c2ab81..50f5ff9 100644 (file)
@@ -105,7 +105,7 @@ server 7833
 >
 *eof
 ****
-exim -odi -bs -DOPT='retry=10s'
+exim -odi -bs -DOPT='127.0.0.1 7833 retry=10s'
 ehlo test.ex
 mail from:<>
 rcpt to:<userx@test.ex>
@@ -163,7 +163,66 @@ server -i 2 7833
 >
 *eof
 ****
-exim -odi -bs -DOPT='retry=4s'
+exim -odi -bs -DOPT='127.0.0.1 7833 retry=4s'
+ehlo test.ex
+mail from:<>
+rcpt to:<userx@test.ex>
+data
+Content-type: text/plain
+
+test
+.
+quit
+****
+#
+#
+#
+# Multiple servers, prioritised, with timeout spec; first one fails
+# List separator changed
+server 7833
+<REPORT SPAMC
+<User:
+<Content-length:
+<
+<From 
+<X-Envelope-From
+<X-Envelope-To
+<Received: 
+<      by 
+<      (envelope
+<      id 
+<      for 
+<Content-type: text/plain
+<Message-Id:
+<From:
+<Date:
+<
+<test
+>SPAMD/1.1 0 EX_OK
+>Spam: False ; 4.5 / 5.0
+>
+>Spam detection software, running on the system "demo",
+>has NOT identified this incoming email as spam.  The original
+>message has been attached to this so you can view it or label
+>similar future email.  If you have any questions, see
+>@@CONTACT_ADDRESS@@ for details.
+>
+>Content preview:  test [...] 
+>
+>Content analysis details:   (4.5 points, 5.0 required)
+>
+> pts rule name              description
+>---- ---------------------- --------------------------------------------------
+>-1.0 ALL_TRUSTED            Passed through trusted hosts only via SMTP
+> 1.2 MISSING_HEADERS        Missing To: header
+> 1.0 MISSING_FROM           Missing From: header
+> 1.8 MISSING_SUBJECT        Missing Subject: header
+> 1.4 MISSING_DATE           Missing Date: header
+> 0.1 MISSING_MID            Missing Message-Id: header
+>
+*eof
+****
+exim -odi -bs -DOPT='<; 127.0.0.1 7833 ; ::1 7834 pri=2 tmo=2s'
 ehlo test.ex
 mail from:<>
 rcpt to:<userx@test.ex>
index 9220c7d..cdc7677 100644 (file)
 354 Enter message, ending with "." on a line by itself\r
 250 OK id=10HmaZ-0005vi-00\r
 221 myhost.test.ex closing connection\r
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250-myhost.test.ex Hello CALLER at test.ex\r
+250-SIZE 52428800\r
+250-8BITMIME\r
+250-PIPELINING\r
+250 HELP\r
+250 OK\r
+250 Accepted\r
+354 Enter message, ending with "." on a line by itself\r
+250 OK id=10HmbA-0005vi-00\r
+221 myhost.test.ex closing connection\r
 
 ******** SERVER ********
 Listening on port 7833 ... 
@@ -166,3 +177,47 @@ Connection request from [127.0.0.1]
 >
 Expected EOF read from client
 End of script
+Listening on port 7833 ... 
+Connection request from [127.0.0.1]
+<REPORT SPAMC/1.2
+<User: nobody
+<Content-length: 479
+<
+<From MAILER-DAEMON Tue Mar 02 09:44:33 1999
+<X-Envelope-From: <CALLER@myhost.test.ex>
+<X-Envelope-To: userx@test.ex
+<Received: from CALLER (helo=test.ex)
+<      by myhost.test.ex with local-esmtp (Exim x.yz)
+<      (envelope-from <CALLER@myhost.test.ex>)
+<      id 10HmbA-0005vi-00
+<      for userx@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+<Content-type: text/plain
+<Message-Id: <E10HmbA-0005vi-00@myhost.test.ex>
+<From: CALLER_NAME <CALLER@myhost.test.ex>
+<Date: Tue, 2 Mar 1999 09:44:33 +0000
+<
+<test
+>SPAMD/1.1 0 EX_OK
+>Spam: False ; 4.5 / 5.0
+>
+>Spam detection software, running on the system "demo",
+>has NOT identified this incoming email as spam.  The original
+>message has been attached to this so you can view it or label
+>similar future email.  If you have any questions, see
+>@@CONTACT_ADDRESS@@ for details.
+>
+>Content preview:  test [...]
+>
+>Content analysis details:   (4.5 points, 5.0 required)
+>
+> pts rule name              description
+>---- ---------------------- --------------------------------------------------
+>-1.0 ALL_TRUSTED            Passed through trusted hosts only via SMTP
+> 1.2 MISSING_HEADERS        Missing To: header
+> 1.0 MISSING_FROM           Missing From: header
+> 1.8 MISSING_SUBJECT        Missing Subject: header
+> 1.4 MISSING_DATE           Missing Date: header
+> 0.1 MISSING_MID            Missing Message-Id: header
+>
+Expected EOF read from client
+End of script