You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spamassassin.apache.org by he...@apache.org on 2018/11/08 10:53:47 UTC

svn commit: r1846123 - in /spamassassin/trunk: MANIFEST UPGRADE lib/Mail/SpamAssassin/Plugin/AuthRes.pm t/all_modules.t t/authres.t t/data/nice/authres

Author: hege
Date: Thu Nov  8 10:53:46 2018
New Revision: 1846123

URL: http://svn.apache.org/viewvc?rev=1846123&view=rev
Log:
New AuthRes plugin - Bug 6918

Added:
    spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/AuthRes.pm
    spamassassin/trunk/t/authres.t   (with props)
    spamassassin/trunk/t/data/nice/authres
Modified:
    spamassassin/trunk/MANIFEST
    spamassassin/trunk/UPGRADE
    spamassassin/trunk/t/all_modules.t

Modified: spamassassin/trunk/MANIFEST
URL: http://svn.apache.org/viewvc/spamassassin/trunk/MANIFEST?rev=1846123&r1=1846122&r2=1846123&view=diff
==============================================================================
--- spamassassin/trunk/MANIFEST (original)
+++ spamassassin/trunk/MANIFEST Thu Nov  8 10:53:46 2018
@@ -75,6 +75,7 @@ lib/Mail/SpamAssassin/Plugin/ASN.pm
 lib/Mail/SpamAssassin/Plugin/AWL.pm
 lib/Mail/SpamAssassin/Plugin/AccessDB.pm
 lib/Mail/SpamAssassin/Plugin/AntiVirus.pm
+lib/Mail/SpamAssassin/Plugin/AuthRes.pm
 lib/Mail/SpamAssassin/Plugin/AutoLearnThreshold.pm
 lib/Mail/SpamAssassin/Plugin/Bayes.pm
 lib/Mail/SpamAssassin/Plugin/BodyEval.pm
@@ -230,6 +231,7 @@ t/README
 t/SATest.pl
 t/SATest.pm
 t/all_modules.t
+t/authres.t
 t/autolearn.t
 t/autolearn_force.t
 t/autolearn_force_fail.t
@@ -325,6 +327,7 @@ t/data/nice/013
 t/data/nice/014
 t/data/nice/015
 t/data/nice/016
+t/data/nice/authres
 t/data/nice/base64.txt
 t/data/nice/crlf-endings
 t/data/nice/dkim/AddedVtag_07

Modified: spamassassin/trunk/UPGRADE
URL: http://svn.apache.org/viewvc/spamassassin/trunk/UPGRADE?rev=1846123&r1=1846122&r2=1846123&view=diff
==============================================================================
--- spamassassin/trunk/UPGRADE (original)
+++ spamassassin/trunk/UPGRADE Thu Nov  8 10:53:46 2018
@@ -76,6 +76,8 @@ Note for Users Upgrading to SpamAssassin
 
 - New dns_block_rule option handles blocked DNSBLs
 
+- New AuthRes module to process Authentication-Results headers (unfinished)
+
 Note for Users Upgrading to SpamAssassin 3.4.2
 ----------------------------------------------
 

Added: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/AuthRes.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/AuthRes.pm?rev=1846123&view=auto
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/AuthRes.pm (added)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/AuthRes.pm Thu Nov  8 10:53:46 2018
@@ -0,0 +1,536 @@
+# <@LICENSE>
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to you under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at:
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# </...@LICENSE>
+
+=head1 NAME
+
+Mail::SpamAssassin::Plugin::AuthRes - use Authentication-Results header fields
+
+=head1 SYNOPSIS
+
+=head2 SpamAssassin configuration:
+
+loadplugin     Mail::SpamAssassin::Plugin::AuthRes
+
+=head1 DESCRIPTION
+
+This plugin parses Authentication-Results header fields and can supply the
+results obtained to other plugins, so as to avoid repeating checks that have
+been performed already.
+
+=cut
+
+package Mail::SpamAssassin::Plugin::AuthRes;
+
+use Mail::SpamAssassin::Plugin;
+use Mail::SpamAssassin::Logger;
+use strict;
+use warnings;
+# use bytes;
+use re 'taint';
+
+our @ISA = qw(Mail::SpamAssassin::Plugin);
+
+# list of valid methods and values
+# https://www.iana.org/assignments/email-auth/email-auth.xhtml
+my %method_result = (
+  'auth' => {'fail'=>1,'none'=>1,'pass'=>1,'permerror'=>1,'temperror'=>1},
+  'dkim' => {'fail'=>1,'neutral'=>1,'none'=>1,'pass'=>1,'permerror'=>1,'policy'=>1,'temperror'=>1},
+  'dkim-adsp' => {'discard'=>1,'fail'=>1,'none'=>1,'nxdomain'=>1,'pass'=>1,'permerror'=>1,'temperror'=>1,'unknown'=>1},
+  'dkim-atps' => {'fail'=>1,'none'=>1,'pass'=>1,'permerror'=>1,'temperror'=>1},
+  'dmarc' => {'fail'=>1,'none'=>1,'pass'=>1,'permerror'=>1,'temperror'=>1},
+  'domainkeys' => {'fail'=>1,'neutral'=>1,'none'=>1,'permerror'=>1,'policy'=>1,'pass'=>1,'temperror'=>1},
+  'iprev' => {'fail'=>1,'pass'=>1,'permerror'=>1,'temperror'=>1},
+  'rrvs' => {'fail'=>1,'none'=>1,'pass'=>1,'permerror'=>1,'temperror'=>1,'unknown'=>1},
+  'sender-id' => {'fail'=>1,'hardfail'=>1,'neutral'=>1,'none'=>1,'pass'=>1,'permerror'=>1,'policy'=>1,'softfail'=>1,'temperror'=>1},
+  'smime' => {'fail'=>1,'neutral'=>1,'none'=>1,'pass'=>1,'permerror'=>1,'policy'=>1,'temperror'=>1},
+  'spf' => {'fail'=>1,'hardfail'=>1,'neutral'=>1,'none'=>1,'pass'=>1,'permerror'=>1,'policy'=>1,'softfail'=>1,'temperror'=>1},
+  'vbr' => {'fail'=>1,'none'=>1,'pass'=>1,'permerror'=>1,'temperror'=>1},
+);
+my %method_ptype_prop = (
+  'auth' => {'smtp' => {'auth'=>1,'mailfrom'=>1}},
+  'dkim' => {'header' => {'d'=>1,'i'=>1,'b'=>1}},
+  'dkim-adsp' => {'header' => {'from'=>1}},
+  'dkim-atps' => {'header' => {'from'=>1}},
+  'dmarc' => {'header' => {'from'=>1}},
+  'domainkeys' => {'header' => {'d'=>1,'from'=>1,'sender'=>1}},
+  'iprev' => {'policy' => {'iprev'=>1}},
+  'rrvs' => {'smtp' => {'rcptto'=>1}},
+  'sender-id' => {'header' => {'*'=>1}},
+  'smime' => {'body' => {'smime-part'=>1,'smime-identifer'=>1,'smime-serial'=>1,'smime-issuer'=>1}},
+  'spf' => {'smtp' => {'mailfrom'=>1,'helo'=>1}},
+  'vbr' => {'header' => {'md'=>1,'mv'=>1}},
+);
+      
+# Some MIME helpers
+my $QUOTED_STRING = qr/"((?:[^"\\]++|\\.)*+)"?/;
+my $TOKEN = qr/[^\s\x00-\x1f\x80-\xff\(\)\<\>\@\,\;\:\/\[\]\?\=\"]+/;
+my $ATOM = qr/[a-zA-Z0-9\@\!\#\$\%\&\\\'\*\+\-\/\=\?\^\_\`\{\|\}\~]+/;
+
+sub new {
+  my ($class, $mailsa) = @_;
+
+  # the usual perlobj boilerplate to create a subclass object
+  $class = ref($class) || $class;
+  my $self = $class->SUPER::new($mailsa);
+  bless ($self, $class);
+
+  $self->set_config($mailsa->{conf});
+
+  # process first as other plugins might depend on us
+  $self->register_method_priority("parsed_metadata", -10);
+
+  $self->register_eval_rule("check_authres_result");
+
+  return $self;
+}
+
+sub set_config {
+  my ($self, $conf) = @_;
+  my @cmds;
+
+=head1 ADMINISTRATOR OPTIONS
+
+=over
+
+=item authres_networks internal/trusted/all    (default: internal)
+
+Process Authenticated-Results headers set by servers from these networks
+(refers to SpamAssassin *_networks zones).  Any header outside this is
+completely ignored and affects any module settings.
+
+ internal   = internal_networks
+ trusted    = internal_networks + trusted_networks
+ all        = all above + all external
+
+Setting "all" makes sense only if your MX servers filter properly all
+incoming A-R headers.  Even then it might be safer to just extend SA
+trusted_networks to any external servers whose A-R you want to see, and use
+the "trusted" setting.
+
+=cut
+
+  push (@cmds, {
+    setting => 'authres_networks',
+    is_admin => 1,
+    default => 'internal',
+    type => $Mail::SpamAssassin::Conf::CONF_TYPE_STRING,
+    code => sub {
+      my ($self, $key, $value, $line) = @_;
+      if (!defined $value || $value =~ /^$/) {
+        return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE;
+      }
+      $value = lc($value);
+      if ($value =~ /^(?:internal|trusted|all)$/) {
+        $self->{authres_networks} = $value;
+      } else {
+        return $Mail::SpamAssassin::Conf::INVALID_VALUE;
+      }
+    }
+  });
+
+=item authres_ignored_authserv authservid1 id2 ...   (default: none)
+
+Ignored authentication server IDs (the domain-name-like first word of
+Authentication-Results field, also known as C<authserv-id>).
+
+Any A-R header is ignored if match is found.
+
+=cut
+
+  push (@cmds, {
+    setting => 'authres_ignored_authserv',
+    is_admin => 1,
+    default => {},
+    type => $Mail::SpamAssassin::Conf::CONF_TYPE_HASH_KEY_VALUE,
+    code => sub {
+      my ($self, $key, $value, $line) = @_;
+      if (!defined $value || $value =~ /^$/) {
+        return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE;
+      }
+      foreach my $id (split(/\s+/, lc $value)) {
+        $self->{authres_ignored_authserv}->{$id} = 1;
+      }
+    }
+  });
+
+=item authres_trusted_authserv authservid1 id2 ...   (default: none)
+
+Trusted authentication server IDs (the domain-name-like first word of
+Authentication-Results field, also known as C<authserv-id>).
+
+Note that if set, ALL A-R headers are ignored unless a match is found.
+
+=back
+
+=cut
+
+  push (@cmds, {
+    setting => 'authres_trusted_authserv',
+    is_admin => 1,
+    default => {},
+    type => $Mail::SpamAssassin::Conf::CONF_TYPE_HASH_KEY_VALUE,
+    code => sub {
+      my ($self, $key, $value, $line) = @_;
+      if (!defined $value || $value =~ /^$/) {
+        return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE;
+      }
+      foreach my $id (split(/\s+/, lc $value)) {
+        $self->{authres_trusted_authserv}->{$id} = 1;
+      }
+    }
+  });
+
+  $conf->{parser}->register_commands(\@cmds);
+}
+
+=head1 METADATA
+
+Parsed headers are stored in $pms-E<gt>{authres_parsed}, as a hash of array
+of hashes where results are collected by method.  For example, the header
+field:
+
+  Authentication-Results: server.example.com;
+    spf=pass smtp.mailfrom=bounce.example.org;
+    dkim=pass header.i=@example.org;
+    dkim=fail header.i=@another.signing.domain.example
+
+Produces the following structure:
+
+ $pms->{authres_parsed} = {
+   'dkim' => [
+     {
+       'properties' => {
+         'header' => {
+           'i' => '@example.org'
+         }
+       },
+       'authserv' => 'server.example.com',
+       'result' => 'pass',
+       'version' => 1,
+       'reason' => ''
+     },
+     {
+       'properties' => {
+         'header' => {
+           'i' => '@another.signing.domain.example'
+         }
+       },
+       'result' => 'fail',
+       'authserv' => 'server.example.com',
+       'version' => 1,
+       'reason' => ''
+     },
+   ],
+ }
+
+Within each array, the order of results is the original, which should be most
+recent results first.
+
+For checking result of methods, $pms-E<gt>{authres_result} is available:
+
+ $pms->{authres_result} = {
+   'dkim' => 'pass',
+   'spf' => 'fail',
+ }
+
+=head1 EVAL FUNCTIONS
+
+=over 4
+
+=item header RULENAME eval:check_authres_result(method, result)
+
+Can be used to check results.
+
+  ifplugin Mail::SpamAssassin::Plugin::AuthRes
+  ifplugin !(Mail::SpamAssassin::Plugin::SPF)
+    header  SPF_PASS      eval:check_authres_result('spf', 'pass')
+    header  SPF_FAIL      eval:check_authres_result('spf', 'fail')
+    header  SPF_SOFTFAIL  eval:check_authres_result('spf', 'softfail')
+    header  SPF_TEMPFAIL  eval:check_authres_result('spf', 'tempfail')
+  endif
+  ifplugin !(Mail::SpamAssassin::Plugin::DKIM)
+    header  DKIM_VERIFIED  eval:check_authres_result('dkim', 'pass')
+    header  DKIM_INVALID   eval:check_authres_result('dkim', 'fail')
+  endif
+  endif
+
+=back
+
+=cut
+
+sub check_authres_result {
+  my ($self, $pms, $method, $wanted_result) = @_;
+
+  my $result = $pms->{authres_result}->{$method};
+  $wanted_result = lc($wanted_result);
+
+  if ($wanted_result eq 'missing') {
+    return !defined($result) ? 1 : 0;
+  }
+
+  return ($wanted_result eq $result);
+}
+
+sub parsed_metadata {
+  my ($self, $opts) = @_;
+
+  my $pms = $opts->{permsgstatus};
+
+  my @authres;
+  my $nethdr;
+
+  if ($pms->{conf}->{authres_networks} eq 'internal') {
+    $nethdr = 'ALL-INTERNAL';
+  } elsif ($pms->{conf}->{authres_networks} eq 'trusted') {
+    $nethdr = 'ALL-TRUSTED';
+  } else {
+    $nethdr = 'ALL';
+  }
+
+  foreach my $hdr (split(/^/m, $pms->get($nethdr))) {
+    if ($hdr =~ /^Authentication-Results:\s*(.+)/i) {
+      push @authres, $1;
+    }
+  }
+
+  if (!@authres) {
+    dbg("authres: no Authentication-Results headers found from %s",
+      $pms->{conf}->{authres_networks});
+    return 0;
+  }
+
+  foreach (@authres) {
+    eval {
+      $self->parse_authres($pms, $_);
+    } or do {
+      dbg("authres: skipping header, $@");
+    }
+  }
+
+  $pms->{authres_result} = {};
+  # Set $pms->{authres_result} info for all found methods
+  # 'pass' will always win if multiple results
+  foreach my $method (keys %method_result) {
+    my $parsed = $pms->{authres_parsed}->{$method};
+    next if !$parsed;
+    foreach my $pref (@$parsed) {
+      if (!$pms->{authres_result}->{$method} ||
+            $pref->{result} eq 'pass')
+      {
+        $pms->{authres_result}->{$method} = $pref->{result};
+      }
+    }
+  }
+
+  if (%{$pms->{authres_result}}) {
+    dbg("authres: results: %s",
+      join(' ', map { $_.'='.$pms->{authres_result}->{$_} }
+        sort keys %{$pms->{authres_result}}));
+  } else {
+    dbg("authres: no results");
+  }
+}
+
+sub parse_authres {
+  my ($self, $pms, $hdr) = @_;
+
+  dbg("authres: parsing Authentication-Results: $hdr");
+
+  my $authserv;
+  my $version = 1;
+  my @methods;
+
+  local $_ = $hdr;
+
+  # authserv-id
+  if (!/\G($TOKEN)/gcs) {
+    die("invalid authserv\n");
+  }
+  $authserv = lc($1);
+
+  if (%{$pms->{conf}->{authres_trusted_authserv}}) {
+    if (!$pms->{conf}->{authres_trusted_authserv}->{$authserv}) {
+      die("authserv not trusted: $authserv\n");
+    }
+  }
+  if ($pms->{conf}->{authres_ignored_authserv}->{$authserv}) {
+    die("ignored authserv: $authserv\n");
+  }
+
+  skip_cfws();
+  if (/\G\d+/gcs) { # skip authserv version
+    skip_cfws();
+  }
+  if (!/\G;/gcs) {
+    die("missing delimiter\n");
+  }
+  skip_cfws();
+
+  while (pos() < length()) {
+    my ($method, $result);
+    my $reason = '';
+    my $props = {};
+
+    # skip none method
+    if (/\Gnone\b/igcs) {
+      die("method none\n");
+    }
+
+    # method / version = result
+    if (!/\G([\w-]+)/gcs) {
+      die("invalid method\n");
+    }
+    $method = lc($1);
+    if (!exists $method_result{$method}) {
+      die("unknown method: $method\n");
+    }
+    skip_cfws();
+    if (/\G\//gcs) {
+      skip_cfws();
+      if (!/\G\d+/gcs) {
+        die("invalid $method version\n");
+      }
+      $version = $1;
+      skip_cfws();
+    }
+    if (!/\G=/gcs) {
+      die("missing result for $method: ".substr($_, pos())."\n");
+    }
+    skip_cfws();
+    if (!/\G(\w+)/gcs) {
+      die("invalid result for $method\n");
+    }
+    $result = $1;
+    if (!exists $method_result{$method}{$result}) {
+      die("unknown result for $method: $result\n");
+    }
+    skip_cfws();
+
+    # reason = value
+    if (/\Greason\b/igcs) {
+      skip_cfws();
+      if (!/\G=/gcs) {
+        die("invalid reason\n");
+      }
+      skip_cfws();
+      if (!/\G$QUOTED_STRING|($TOKEN)/gcs) {
+        die("invalid reason\n");
+      }
+      $reason = defined $1 ? $1 : $2;
+      skip_cfws();
+    }
+
+    # ptype.property = value
+    while (pos() < length()) {
+      my ($ptype, $property, $value);
+
+      # ptype
+      if (!/\G(\w+)/gcs) {
+        die("invalid ptype: ".substr($_,pos())."\n");
+      }
+      $ptype = lc($1);
+      if (!exists $method_ptype_prop{$method}{$ptype}) {
+        die("unknown ptype: $ptype\n");
+      }
+      skip_cfws();
+
+      # dot
+      if (!/\G\./gcs) {
+        die("missing property\n");
+      }
+      skip_cfws();
+
+      # property
+      if (!/\G(\w+)/gcs) {
+        die("invalid property\n");
+      }
+      $property = lc($1);
+      if (!exists $method_ptype_prop{$method}{$ptype}{$property} &&
+          !exists $method_ptype_prop{$method}{$ptype}{'*'}) {
+        die("unknown property for $ptype: $property\n");
+      }
+      skip_cfws();
+
+      # =
+      if (!/\G=/gcs) {
+        die("missing property value\n");
+      }
+      skip_cfws();
+
+      # value:
+      # The grammar is ( value / [ [ local-part ] "@" ] domain-name )
+      # where value := token / quoted-string
+      # and local-part := dot-atom / quoted-string / obs-local-part
+      if (!/\G$QUOTED_STRING|($ATOM(?:\.$ATOM)*|$TOKEN)(?=(?:[\s;]|$))/gcs) {
+        die("invalid $ptype.$property value\n");
+      }
+      $value = defined $1 ? $1 : $2;
+      skip_cfws();
+
+      $props->{$ptype}->{$property} = $value;
+
+      if (/\G(?:;|$)/gcs) {
+        skip_cfws();
+        last;
+      }
+    }
+
+    push @methods, [$method, {
+        'authserv' => $authserv,
+        'version' => $version,
+        'result' => $result,
+        'reason' => $reason,
+        'properties' => $props,
+        }];
+  }
+
+  # paranoid check..
+  if (pos() < length()) {
+    die("parse ended prematurely?\n");
+  }
+
+  # Pushed to pms only if header parsed completely
+  foreach my $marr (@methods) {
+    push @{$pms->{authres_parsed}->{$marr->[0]}}, $marr->[1];
+  }
+
+  return 1;
+}
+
+# skip whitespace and comments
+sub skip_cfws {
+  /\G\s*/gcs;
+  if (/\G\(/gcs) {
+    my $i = 1;
+    while (/\G.*?([()]|\z)/gcs) {
+      $1 eq ')' ? $i-- : $i++;
+      last if !$i;
+    }
+    die("comment not ended\n") if $i;
+    /\G\s*/gcs;
+  }
+}
+
+#sub check_cleanup {
+#  my ($self, $opts) = @_;
+#  my $pms = $opts->{permsgstatus};
+#  use Data::Dumper;
+#  print STDERR Dumper($pms->{authres_parsed});
+#  print STDERR Dumper($pms->{authres_result});
+#}
+
+1;

Modified: spamassassin/trunk/t/all_modules.t
URL: http://svn.apache.org/viewvc/spamassassin/trunk/t/all_modules.t?rev=1846123&r1=1846122&r2=1846123&view=diff
==============================================================================
--- spamassassin/trunk/t/all_modules.t (original)
+++ spamassassin/trunk/t/all_modules.t Thu Nov  8 10:53:46 2018
@@ -56,6 +56,7 @@ loadplugin Mail::SpamAssassin::Plugin::H
 loadplugin Mail::SpamAssassin::Plugin::ResourceLimits
 loadplugin Mail::SpamAssassin::Plugin::FromNameSpoof
 loadplugin Mail::SpamAssassin::Plugin::Phishing
+loadplugin Mail::SpamAssassin::Plugin::AuthRes
 ");
 
 tstprefs("

Added: spamassassin/trunk/t/authres.t
URL: http://svn.apache.org/viewvc/spamassassin/trunk/t/authres.t?rev=1846123&view=auto
==============================================================================
--- spamassassin/trunk/t/authres.t (added)
+++ spamassassin/trunk/t/authres.t Thu Nov  8 10:53:46 2018
@@ -0,0 +1,146 @@
+#!/usr/bin/perl
+
+use lib '.'; 
+use lib 't';
+use SATest; 
+sa_t_init("authres");
+
+use Test::More;
+plan tests => 44;
+
+# ---------------------------------------------------------------------------
+
+tstpre ("
+loadplugin Mail::SpamAssassin::Plugin::AuthRes
+");
+
+## with internal networks
+
+tstprefs("
+clear_internal_networks
+clear_trusted_networks
+internal_networks 212.17.35.15
+trusted_networks 212.17.35.15
+trusted_networks 141.154.95.22
+");
+
+%patterns = (
+        'parsing Authentication-Results: authrestest1int', 'hdr1',
+        'parsing Authentication-Results: authrestest2int', 'hdr2',
+        'parsing Authentication-Results: authrestest3int', 'hdr3',
+        'parsing Authentication-Results: authrestest4int', 'hdr4',
+        'parsing Authentication-Results: authrestest5int', 'hdr5',
+        'parsing Authentication-Results: authrestest6int', 'hdr6',
+        'authres: results: dkim=pass dmarc=none spf=pass', 'results',
+            );
+
+%anti_patterns = (
+        'parsing Authentication-Results: authrestest7tru', 'hdr7',
+        'parsing Authentication-Results: authrestest8ext', 'hdr8',
+        'authres: no Authentication-Results headers found', 'nohdr',
+        'authres: skipping header,', 'skipping',
+            );
+
+sarun ("-D authres -L -t < data/nice/authres 2>&1", \&patterns_run_cb);
+ok_all_patterns();
+
+
+## with trusted networks included
+
+tstprefs("
+clear_internal_networks
+clear_trusted_networks
+internal_networks 212.17.35.15
+trusted_networks 212.17.35.15
+trusted_networks 141.154.95.22
+
+authres_networks trusted
+");
+
+%patterns = (
+        'parsing Authentication-Results: authrestest1int', 'hdr1',
+        'parsing Authentication-Results: authrestest2int', 'hdr2',
+        'parsing Authentication-Results: authrestest3int', 'hdr3',
+        'parsing Authentication-Results: authrestest4int', 'hdr4',
+        'parsing Authentication-Results: authrestest5int', 'hdr5',
+        'parsing Authentication-Results: authrestest6int', 'hdr6',
+        'parsing Authentication-Results: authrestest7tru', 'hdr7',
+        'authres: results: dkim=pass dmarc=none spf=pass', 'results',
+            );
+
+%anti_patterns = (
+        'parsing Authentication-Results: authrestest8ext', 'hdr8',
+        'authres: no Authentication-Results headers found', 'nohdr',
+        'authres: skipping header,', 'skipping',
+            );
+
+sarun ("-D authres -L -t < data/nice/authres 2>&1", \&patterns_run_cb);
+ok_all_patterns();
+
+
+## with all networks (test ignore also)
+
+tstprefs("
+clear_internal_networks
+clear_trusted_networks
+internal_networks 212.17.35.15
+trusted_networks 212.17.35.15
+trusted_networks 141.154.95.22
+
+authres_networks all
+authres_ignored_authserv authrestest3int authrestest4int
+");
+
+%patterns = (
+        'parsing Authentication-Results: authrestest1int', 'hdr1',
+        'parsing Authentication-Results: authrestest2int', 'hdr2',
+        'parsing Authentication-Results: authrestest3int', 'hdr3',
+        'parsing Authentication-Results: authrestest4int', 'hdr4',
+        'parsing Authentication-Results: authrestest5int', 'hdr5',
+        'parsing Authentication-Results: authrestest6int', 'hdr6',
+        'parsing Authentication-Results: authrestest7tru', 'hdr7',
+        'parsing Authentication-Results: authrestest8ext', 'hdr8',
+        'authres: results: dkim=pass dmarc=none spf=pass', 'results',
+        'authres: skipping header, ignored authserv: authrestest3int', 'skip3',
+        'authres: skipping header, ignored authserv: authrestest4int', 'skip4',
+            );
+
+%anti_patterns = (
+        'authres: no Authentication-Results headers found', 'nohdr',
+            );
+
+sarun ("-D authres -L -t < data/nice/authres 2>&1", \&patterns_run_cb);
+ok_all_patterns();
+
+## with all networks (test trusted also)
+
+tstprefs("
+clear_internal_networks
+clear_trusted_networks
+internal_networks 212.17.35.15
+trusted_networks 212.17.35.15
+trusted_networks 141.154.95.22
+
+authres_networks all
+authres_trusted_authserv authrestest6int
+");
+
+%patterns = (
+        'dbg: authres: skipping header, authserv not trusted: authrestest1int', 'skip1',
+        'dbg: authres: skipping header, authserv not trusted: authrestest2int', 'skip2',
+        'dbg: authres: skipping header, authserv not trusted: authrestest3int', 'skip3',
+        'dbg: authres: skipping header, authserv not trusted: authrestest4int', 'skip4',
+        'dbg: authres: skipping header, authserv not trusted: authrestest5int', 'skip5',
+        'dbg: authres: skipping header, authserv not trusted: authrestest7tru', 'skip6',
+        'dbg: authres: skipping header, authserv not trusted: authrestest8ext', 'skip7',
+        'parsing Authentication-Results: authrestest6int', 'parsing',
+        'authres: results: dkim=fail', 'results',
+            );
+
+%anti_patterns = (
+        'authres: no Authentication-Results headers found', 'nohdr',
+            );
+
+sarun ("-D authres -L -t < data/nice/authres 2>&1", \&patterns_run_cb);
+ok_all_patterns();
+

Propchange: spamassassin/trunk/t/authres.t
------------------------------------------------------------------------------
    svn:executable = *

Added: spamassassin/trunk/t/data/nice/authres
URL: http://svn.apache.org/viewvc/spamassassin/trunk/t/data/nice/authres?rev=1846123&view=auto
==============================================================================
--- spamassassin/trunk/t/data/nice/authres (added)
+++ spamassassin/trunk/t/data/nice/authres Thu Nov  8 10:53:46 2018
@@ -0,0 +1,99 @@
+From jm@dogma.slashnull.org  Wed May 16 00:40:34 2001
+Return-Path: <jm...@dogma.slashnull.org>
+Delivered-To: jm@netnoteinc.com
+Received: from dogma.slashnull.org (dogma.slashnull.org [212.17.35.15]) by
+    mail.netnoteinc.com (Postfix) with ESMTP id 830E5115158 for
+    <jm...@netnoteinc.com>; Tue, 15 May 2001 23:40:33 +0000 (Eire)
+Authentication-Results: authrestest1int;
+    spf=pass smtp.mailfrom=bounce.example.org;
+    dkim=pass header.i=@example.org;
+    dkim=fail header.i=@another.signing.domain.example
+Authentication-Results: authrestest2int; dmarc=none (p=none dis=none) header.from=ximian.com
+authentication-Results: authrestest3int; spf=fail smtp.mailfrom=dogma.slashnull.org
+Authentication-Results: authrestest4int 2; spf=fail reason (BAH) = "just some (<>.%&! reason" smtp.mailfrom=dogma.slashnull.org
+Authentication-RESULTS:  authrestest5int;
+        dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b=SI+iqkld;
+Authentication-Results: authrestest6int;
+        dkim=fail (2048-bit key; unprotected) header.d=gmail.com header.i=" foo bar \"xyz\"@gmail.com" header.b=SI+iqkld;
+Received: (from jm@localhost) by dogma.slashnull.org (8.9.3/8.9.3) id
+    AAA30873 for jm@netnoteinc.com; Wed, 16 May 2001 00:40:33 +0100
+Received: from trna.ximian.com ([141.154.95.22]) by dogma.slashnull.org
+    (8.9.3/8.9.3) with ESMTP id AAA30867 for <jm...@jmason.org>;
+    Wed, 16 May 2001 00:40:31 +0100
+Authentication-Results: authrestest7tru; spf=fail smtp.mailfrom=last.trusted@example.com
+Received: from trna.ximian.com (IDENT:nobody@localhost [127.0.0.1]) by
+    trna.ximian.com (8.9.3/8.9.3) with ESMTP id SAA19408; Tue, 15 May 2001
+    18:26:07 -0400
+Received: from milkplus (62-122-4-47.flat.galactica.it [62.122.4.47]) by
+    trna.ximian.com (8.9.3/8.9.3) with ESMTP id RAA19544; Tue, 15 May 2001
+    17:31:24 -0400
+Received: by milkplus (Postfix, from userid 1000) id D3FDD10B051;
+    Tue, 15 May 2001 17:31:22 -0400 (EDT)
+Authentication-Results: authrestest8ext; spf=pass smtp.mailfrom=untrusted@example.com
+From: "Ximian, Inc." <ev...@ximian.com>
+To: announce@ximian.com
+Content-Type: text/plain
+X-Mailer: Evolution/0.10 (Preview Release)
+X-Loop: just so a test passes
+Date: 15 May 2001 17:31:22 -0400
+Message-Id: <98...@milkplus>
+MIME-Version: 1.0
+Subject: [HC Announce] Ximian Evolution 0.10 "Tasmanian Devil" is Now
+    Available!
+Sender: announce-admin@helixcode.com
+Errors-To: announce-admin@helixcode.com
+X-Mailman-Version: 1.1
+Precedence: bulk
+X-Hashcash: 0:040315:test@example.com:69781c87bae95c03
+X-hashcash: 1:20:040806:test1@example.com:test=foo:482b788d12eb9b56:2a3349
+List-Id: Announcements about Ximian. <announce.helixcode.com>
+X-Beenthere: announce@helixcode.com
+X-Spam-Status: No, hits=2 required=5
+
+A new preview release of Ximian Evolution is now available.  Evolution
+is a personal and workgroup information management tool that seamlessly
+combines email, calendar, address book and more.  Its extensive network
+support lets you connect to a wide range of services.  Release 0.10
+includes a host of new features and fixes.
+
+TO GET THE EVOLUTION PREVIEW RELEASE
+
+-   For those of you using Ximian GNOME, this version can be installed
+    by subscribing to the Evolution channel in Red Carpet (System -> Get
+    Software).
+
+-   To download the preview release from the Ximian web site, go to:
+    http://www.ximian.com/apps/evolution-preview/index.php3
+
+TO GET SOURCE CODE
+
+You can also get the Evolution source tarball here:
+
+        ftp://ftp.gnome.org/pub/GNOME/unstable/sources/evolution
+
+    Evolution also requires Gal (0.7), GtkHTML (0.8.2), Bonobo (1.0),
+    OAF (0.6.2), GNOME VFS (1.0), libunicode (0.4.gnome), GNOME Print
+    (0.25) and ORBit (0.5.6).
+
+        ftp://ftp.gnome.org/pub/GNOME/unstable/sources/gal
+        ftp://ftp.gnome.org/pub/GNOME/unstable/sources/gtkhtml
+        ftp://ftp.gnome.org/pub/GNOME/unstable/sources/bonobo
+        ftp://ftp.gnome.org/pub/GNOME/unstable/sources/oaf
+        ftp://ftp.gnome.org/pub/GNOME/unstable/sources/gnome-vfs
+        ftp://ftp.gnome.org/pub/GNOME/unstable/sources/libunicode
+        ftp://ftp.gnome.org/pub/GNOME/stable/sources/gnome-print
+        ftp://ftp.gnome.org/pub/GNOME/stable/sources/ORBit
+
+TO VIEW 0.10 RELEASE NOTES
+
+The 0.10 release notes are available at:
+http://www.ximian.com/newsitems/evolution-0.10-announce.php3
+
+
+
+_______________________________________________
+Announce maillist  -  Announce@helixcode.com
+http://lists.helixcode.com/mailman/listinfo/announce
+
+
+