You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spamassassin.apache.org by fe...@apache.org on 2006/05/24 22:04:46 UTC

svn commit: r409236 - in /spamassassin/branches/3.1: ./ lib/Mail/SpamAssassin/ lib/Mail/SpamAssassin/Message/Metadata/ lib/Mail/SpamAssassin/Plugin/ t/ t/data/spam/

Author: felicity
Date: Wed May 24 13:04:44 2006
New Revision: 409236

URL: http://svn.apache.org/viewvc?rev=409236&view=rev
Log:
bug 4861, 4760: handle dccifd and dccproc failover properly, backport relays_internal and relays_external code, backport bug 4760 fix so that it's not possible to be in internal_networks without being in trusted_networks as well

Added:
    spamassassin/branches/3.1/t/data/spam/gtubedcc.eml
      - copied unchanged from r409234, spamassassin/trunk/t/data/spam/gtubedcc.eml
    spamassassin/branches/3.1/t/dcc.t
      - copied unchanged from r409234, spamassassin/trunk/t/dcc.t
Modified:
    spamassassin/branches/3.1/MANIFEST
    spamassassin/branches/3.1/lib/Mail/SpamAssassin/Conf.pm
    spamassassin/branches/3.1/lib/Mail/SpamAssassin/Message/Metadata/Received.pm
    spamassassin/branches/3.1/lib/Mail/SpamAssassin/PerMsgStatus.pm
    spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DCC.pm
    spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/SPF.pm
    spamassassin/branches/3.1/t/config.dist

Modified: spamassassin/branches/3.1/MANIFEST
URL: http://svn.apache.org/viewvc/spamassassin/branches/3.1/MANIFEST?rev=409236&r1=409235&r2=409236&view=diff
==============================================================================
--- spamassassin/branches/3.1/MANIFEST (original)
+++ spamassassin/branches/3.1/MANIFEST Wed May 24 13:04:44 2006
@@ -344,6 +344,7 @@
 t/data/spam/bsmtpnull
 t/data/spam/dnsbl.eml
 t/data/spam/gtube.eml
+t/data/spam/gtubedcc.eml
 t/data/spam/spf1
 t/data/spam/spf2
 t/data/spam/spf3
@@ -374,6 +375,7 @@
 t/db_awl_path.t
 t/db_based_whitelist.t
 t/db_based_whitelist_ips.t
+t/dcc.t
 t/debug.t
 t/desc_wrap.t
 t/dnsbl.t

Modified: spamassassin/branches/3.1/lib/Mail/SpamAssassin/Conf.pm
URL: http://svn.apache.org/viewvc/spamassassin/branches/3.1/lib/Mail/SpamAssassin/Conf.pm?rev=409236&r1=409235&r2=409236&view=diff
==============================================================================
--- spamassassin/branches/3.1/lib/Mail/SpamAssassin/Conf.pm (original)
+++ spamassassin/branches/3.1/lib/Mail/SpamAssassin/Conf.pm Wed May 24 13:04:44 2006
@@ -2648,6 +2648,8 @@
                    (note: limited to 50 'stars')
  _RELAYSTRUSTED_   relays used and deemed to be trusted
  _RELAYSUNTRUSTED_ relays used that can not be trusted
+ _RELAYSINTERNAL_  relays used and deemed to be internal
+ _RELAYSEXTERNAL_  relays used and deemed to be external
  _AUTOLEARN_       autolearn status ("ham", "no", "spam", "disabled",
                    "failed", "unavailable")
  _TESTS(,)_        tests hit separated by "," (or other separator)

Modified: spamassassin/branches/3.1/lib/Mail/SpamAssassin/Message/Metadata/Received.pm
URL: http://svn.apache.org/viewvc/spamassassin/branches/3.1/lib/Mail/SpamAssassin/Message/Metadata/Received.pm?rev=409236&r1=409235&r2=409236&view=diff
==============================================================================
--- spamassassin/branches/3.1/lib/Mail/SpamAssassin/Message/Metadata/Received.pm (original)
+++ spamassassin/branches/3.1/lib/Mail/SpamAssassin/Message/Metadata/Received.pm Wed May 24 13:04:44 2006
@@ -68,6 +68,14 @@
   $self->{num_relays_untrusted} = 0;
   $self->{relays_untrusted_str} = '';
 
+  $self->{relays_internal} = [ ];
+  $self->{num_relays_internal} = 0;
+  $self->{relays_internal_str} = '';
+
+  $self->{relays_external} = [ ];
+  $self->{num_relays_external} = 0;
+  $self->{relays_external_str} = '';
+
   $self->{num_relays_unparseable} = 0;
 
   # now figure out what relays are trusted...
@@ -135,6 +143,12 @@
       $in_internal = 0;
     }
 
+    # note: you can't be in internal networks, but not be in a trusted 
+    # net. (bug 4760)
+    if ($in_internal && !$in_trusted) {
+      $in_trusted = 1;
+    }
+
 # OK, infer the trusted/untrusted handover, if we don't have real info.
 # Here's the algorithm used (taken from Dan's mail):
 # 
@@ -262,12 +276,22 @@
       push (@{$self->{relays_untrusted}}, $relay);
       $self->{allow_fetchmail_markers} = 0;
     }
+
+    if ($in_internal) {
+      push (@{$self->{relays_internal}}, $relay);
+    } else {
+      push (@{$self->{relays_external}}, $relay);
+    }
   }
 
   $self->{relays_trusted_str} = join(' ', map { $_->{as_string} }
                     @{$self->{relays_trusted}});
   $self->{relays_untrusted_str} = join(' ', map { $_->{as_string} }
                     @{$self->{relays_untrusted}});
+  $self->{relays_internal_str} = join(' ', map { $_->{as_string} }
+                    @{$self->{relays_internal}});
+  $self->{relays_external_str} = join(' ', map { $_->{as_string} }
+                    @{$self->{relays_external}});
 
   # drop the temp PerMsgStatus object
   delete $self->{dns_pms};
@@ -282,21 +306,31 @@
   if ($self->{msg}->can ("delete_header")) {
     $self->{msg}->delete_header ("X-Spam-Relays-Trusted");
     $self->{msg}->delete_header ("X-Spam-Relays-Untrusted");
+    $self->{msg}->delete_header ("X-Spam-Relays-Internal");
+    $self->{msg}->delete_header ("X-Spam-Relays-External");
  
     if ($self->{msg}->can ("put_metadata")) {
       $self->{msg}->put_metadata ("X-Spam-Relays-Trusted",
 			$self->{relays_trusted_str});
       $self->{msg}->put_metadata ("X-Spam-Relays-Untrusted",
 			$self->{relays_untrusted_str});
+      $self->{msg}->put_metadata ("X-Spam-Relays-Internal",
+			$self->{relays_internal_str});
+      $self->{msg}->put_metadata ("X-Spam-Relays-External",
+			$self->{relays_external_str});
     }
   }
 
   # be helpful; save some cumbersome typing
   $self->{num_relays_trusted} = scalar (@{$self->{relays_trusted}});
   $self->{num_relays_untrusted} = scalar (@{$self->{relays_untrusted}});
+  $self->{num_relays_internal} = scalar (@{$self->{relays_internal}});
+  $self->{num_relays_external} = scalar (@{$self->{relays_external}});
 
   dbg("metadata: X-Spam-Relays-Trusted: ".$self->{relays_trusted_str});
   dbg("metadata: X-Spam-Relays-Untrusted: ".$self->{relays_untrusted_str});
+  dbg("metadata: X-Spam-Relays-Internal: ".$self->{relays_internal_str});
+  dbg("metadata: X-Spam-Relays-External: ".$self->{relays_external_str});
 }
 
 sub lookup_all_ips {
@@ -1224,6 +1258,8 @@
   if ($self->{allow_fetchmail_markers}) {
     dbg("received-header: found fetchmail marker, restarting parse");
     $self->{relays_trusted} = [ ];
+    $self->{relays_internal} = [ ];
+    $self->{relays_external} = [ ];
   } else {
     dbg("received-header: found fetchmail marker outside trusted area, ignored");
   }

Modified: spamassassin/branches/3.1/lib/Mail/SpamAssassin/PerMsgStatus.pm
URL: http://svn.apache.org/viewvc/spamassassin/branches/3.1/lib/Mail/SpamAssassin/PerMsgStatus.pm?rev=409236&r1=409235&r2=409236&view=diff
==============================================================================
--- spamassassin/branches/3.1/lib/Mail/SpamAssassin/PerMsgStatus.pm (original)
+++ spamassassin/branches/3.1/lib/Mail/SpamAssassin/PerMsgStatus.pm Wed May 24 13:04:44 2006
@@ -1351,6 +1351,8 @@
   foreach my $item (qw(
 	relays_trusted relays_trusted_str num_relays_trusted
 	relays_untrusted relays_untrusted_str num_relays_untrusted
+	relays_internal relays_internal_str num_relays_internal
+	relays_external relays_external_str num_relays_external
         num_relays_unparseable
 	))
   {
@@ -1359,6 +1361,8 @@
 
   $self->{tag_data}->{RELAYSTRUSTED} = $self->{relays_trusted_str};
   $self->{tag_data}->{RELAYSUNTRUSTED} = $self->{relays_untrusted_str};
+  $self->{tag_data}->{RELAYSINTERNAL} = $self->{relays_internal_str};
+  $self->{tag_data}->{RELAYSEXTERNAL} = $self->{relays_external_str};
   $self->{tag_data}->{LANGUAGES} = $self->{msg}->get_metadata("X-Languages");
 
   # This should happen before we get called, but just in case.
@@ -1494,6 +1498,14 @@
   # trusted relays list, as string
   elsif ($request eq 'X-Spam-Relays-Trusted') {
     $result = $self->{relays_trusted_str};
+  }
+  # external relays list, as string
+  elsif ($request eq 'X-Spam-Relays-External') {
+    $result = $self->{relays_external_str};
+  }
+  # internal relays list, as string
+  elsif ($request eq 'X-Spam-Relays-Internal') {
+    $result = $self->{relays_internal_str};
   }
   # ToCc: the combined recipients list
   elsif ($request eq 'ToCc') {

Modified: spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DCC.pm
URL: http://svn.apache.org/viewvc/spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DCC.pm?rev=409236&r1=409235&r2=409236&view=diff
==============================================================================
--- spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DCC.pm (original)
+++ spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/DCC.pm Wed May 24 13:04:44 2006
@@ -97,7 +97,7 @@
     type => $Mail::SpamAssassin::Conf::CONF_TYPE_BOOL,
   });
 
-=item dcc_timeout n		(default: 5)
+=item dcc_timeout n		(default: 8)
 
 How many seconds you wait for DCC to complete, before scanning continues
 without the DCC results.
@@ -106,7 +106,7 @@
 
   push (@cmds, {
     setting => 'dcc_timeout',
-    default => 5,
+    default => 8,
     type => $Mail::SpamAssassin::Conf::CONF_TYPE_NUMERIC,
   });
 
@@ -238,14 +238,14 @@
 Specify additional options to the dccproc(8) command. Please note that only
 characters in the range [0-9A-Za-z ,._/-] are allowed for security reasons.
 
-The default is C<-R>.
+The default is C<undef>.
 
 =cut
 
   push (@cmds, {
     setting => 'dcc_options',
     is_admin => 1,
-    default => '-R',
+    default => undef,
     code => sub {
       my ($self, $key, $value, $line) = @_;
       if ($value !~ m{^([0-9A-Za-z ,._/-]+)$}) {
@@ -255,6 +255,28 @@
     }
   });
 
+=item dccifd_options options
+
+Specify additional options to send to the dccifd(8) daemon. Please note that only
+characters in the range [0-9A-Za-z ,._/-] are allowed for security reasons.
+
+The default is C<undef>.
+
+=cut
+
+  push (@cmds, {
+    setting => 'dccifd_options',
+    is_admin => 1,
+    default => undef,
+    code => sub {
+      my ($self, $key, $value, $line) = @_;
+      if ($value !~ m{^([0-9A-Za-z ,._/-]+)$}) {
+	return $Mail::SpamAssassin::Conf::INVALID_VALUE;
+      }
+      $self->{dccifd_options} = $1;
+    }
+  });
+
   $conf->{parser}->register_commands(\@cmds);
 }
 
@@ -352,23 +374,34 @@
     return 0;
   }
 
+  my $client = $permsgstatus->{relays_external}->[0]->{ip};
   if ($self->{dccifd_available}) {
-    return $self->dccifd_lookup($permsgstatus, $full);
+    my $clientname = $permsgstatus->{relays_external}->[0]->{rdns};
+    my $helo = $permsgstatus->{relays_external}->[0]->{helo} || "";
+    if ($client) {
+      if ($clientname) {
+        $client = $client . "\r" . $clientname;
+      }
+    } else {
+      $client = "0.0.0.0";
+    }
+    return $self->dccifd_lookup($permsgstatus, $full, $client, $clientname, $helo);
   }
   else {
-    return $self->dccproc_lookup($permsgstatus, $full);
+    return $self->dccproc_lookup($permsgstatus, $full, $client);
   }
   return 0;
 }
 
 sub dccifd_lookup {
-  my ($self, $permsgstatus, $fulltext) = @_;
+  my ($self, $permsgstatus, $fulltext, $client, $clientname, $helo) = @_;
   my $response = "";
   my %count;
   my $left;
   my $right;
   my $timeout = $self->{main}->{conf}->{dcc_timeout};
   my $sockpath = $self->{main}->{conf}->{dcc_dccifd_path};
+  my $opts = $self->{main}->{conf}->{dccifd_options} || '';
 
   $count{body} = 0;
   $count{fuz1} = 0;
@@ -385,9 +418,9 @@
       Peer => $sockpath) || dbg("dcc: failed to open socket") && die;
 
     # send the options and other parameters to the daemon
-    $sock->print("header\n") || dbg("dcc: failed write") && die; # options
-    $sock->print("0.0.0.0\n") || dbg("dcc: failed write") && die; # client
-    $sock->print("\n") || dbg("dcc: failed write") && die; # HELO value
+    $sock->print("header " . $opts . "\n") || dbg("dcc: failed write") && die; # options
+    $sock->print($client . "\n") || dbg("dcc: failed write") && die; # client
+    $sock->print($helo . "\n") || dbg("dcc: failed write") && die; # HELO value
     $sock->print("\n") || dbg("dcc: failed write") && die; # sender
     $sock->print("unknown\r\n") || dbg("dcc: failed write") && die; # recipients
     $sock->print("\n") || dbg("dcc: failed write") && die; # recipients
@@ -469,7 +502,7 @@
 }
 
 sub dccproc_lookup {
-  my ($self, $permsgstatus, $fulltext) = @_;
+  my ($self, $permsgstatus, $fulltext, $client) = @_;
   my $response = undef;
   my %count;
   my $timeout = $self->{main}->{conf}->{dcc_timeout};
@@ -493,11 +526,12 @@
     my $path = Mail::SpamAssassin::Util::untaint_file_path($self->{main}->{conf}->{dcc_path});
 
     my $opts = $self->{main}->{conf}->{dcc_options} || '';
+    $opts = "-a " . $client . " " . $opts if $client;
 
-    dbg("dcc: opening pipe: " . join(' ', $path, "-H", $opts, "< $tmpf"));
+    dbg("dcc: opening pipe: " . join(' ', $path, "-H", "-x", "0", $opts, "< $tmpf"));
 
     $pid = Mail::SpamAssassin::Util::helper_app_pipe_open(*DCC,
-	$tmpf, 1, $path, "-H", split(' ', $opts));
+	$tmpf, 1, $path, "-H", "-x", "0", split(' ', $opts));
     $pid or die "$!\n";
 
     my @null = <DCC>;
@@ -596,29 +630,103 @@
 sub plugin_report {
   my ($self, $options) = @_;
 
+  return if $self->{options}->{dont_report_to_dcc};
+  $self->get_dcc_interface();
   return if $self->{dcc_disabled};
 
-  if (!defined $self->{dccproc_available}) {
-    $self->is_dccproc_available();
-  }
-
-  if ($self->{dccproc_available} && !$self->{options}->{dont_report_to_dcc}) {
+  # get the metadata from the message so we can pass the external relay information
+  $options->{msg}->extract_message_metadata($options->{report}->{main});
+  my $client = $options->{msg}->{metadata}->{relays_external}->[0]->{ip};
+  if ($self->{dccifd_available}) {
+    my $clientname = $options->{msg}->{metadata}->{relays_external}->[0]->{rdns};
+    my $helo = $options->{msg}->{metadata}->{relays_external}->[0]->{helo} || "";
+    if ($client) {
+      if ($clientname) {
+        $client = $client . "\r" . $clientname;
+      }
+    } else {
+      $client = "0.0.0.0";
+    }
+    if ($self->dccifd_report($options, $options->{text}, $client, $helo)) {
+      $options->{report}->{report_available} = 1;
+      info("reporter: spam reported to DCC");
+      $options->{report}->{report_return} = 1;
+    }
+    else {
+      info("reporter: could not report spam to DCC via dccifd");
+    }
+  } else {
     # use temporary file: open2() is unreliable due to buffering under spamd
     my $tmpf = $options->{report}->create_fulltext_tmpfile($options->{text});
-    if ($self->dcc_report($options, $tmpf)) {
+    
+    if ($self->dcc_report($options, $tmpf, $client)) {
       $options->{report}->{report_available} = 1;
       info("reporter: spam reported to DCC");
       $options->{report}->{report_return} = 1;
     }
     else {
-      info("reporter: could not report spam to DCC");
+      info("reporter: could not report spam to DCC via dccproc");
     }
     $options->{report}->delete_fulltext_tmpfile();
   }
 }
 
+sub dccifd_report {
+  my ($self, $options, $fulltext, $client, $helo) = @_;
+  my $timeout = $self->{main}->{conf}->{dcc_timeout};
+  my $sockpath = $self->{main}->{conf}->{dcc_dccifd_path};
+  my $opts = $self->{main}->{conf}->{dccifd_options} || ''; # instead of header use whatever the report option is
+
+  $options->{report}->enter_helper_run_mode();
+  my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout });
+
+  my $err = $timer->run_and_catch(sub {
+
+    local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" };
+
+    my $sock = IO::Socket::UNIX->new(Type => SOCK_STREAM,
+                                     Peer => $sockpath) || dbg("report: dccifd failed to open socket") && die;
+
+    # send the options and other parameters to the daemon
+    $sock->print("spam " . $opts . "\n") || dbg("report: dccifd failed write") && die; # options
+    $sock->print($client . "\n") || dbg("report: dccifd failed write") && die; # client
+    $sock->print($helo . "\n") || dbg("report: dccifd failed write") && die; # HELO value
+    $sock->print("\n") || dbg("report: dccifd failed write") && die; # sender
+    $sock->print("unknown\r\n") || dbg("report: dccifd failed write") && die; # recipients
+    $sock->print("\n") || dbg("report: dccifd failed write") && die; # recipients
+
+    $sock->print($$fulltext);
+
+    $sock->shutdown(1) || dbg("report: dccifd failed socket shutdown: $!") && die;
+
+    $sock->getline() || dbg("report: dccifd failed read status") && die;
+    $sock->getline() || dbg("report: dccifd failed read multistatus") && die;
+
+    my @ignored = $sock->getlines();
+  });
+
+  $options->{report}->leave_helper_run_mode();
+  
+  if ($timer->timed_out()) {
+    dbg("reporter: DCC report via dccifd timed out after $timeout secs.");
+    return 0;
+  }
+  
+  if ($err) {
+    chomp $err;
+    if ($err eq "__brokenpipe__ignore__") {
+      dbg("reporter: DCC report via dccifd failed: broken pipe");
+    } else {
+      warn("reporter: DCC report via dccifd failed: $err\n");
+    }
+    return 0;
+  }
+  
+  return 1;
+}
+  
 sub dcc_report {
-  my ($self, $options, $tmpf) = @_;
+  my ($self, $options, $tmpf, $client) = @_;
   my $timeout = $options->{report}->{conf}->{dcc_timeout};
 
   # note: not really tainted, this came from system configuration file
@@ -626,6 +734,9 @@
 
   my $opts = $options->{report}->{conf}->{dcc_options} || '';
 
+  # get the metadata from the message so we can pass the external relay information
+  $opts = "-a " . $client . " " . $opts if $client;
+
   my $timer = Mail::SpamAssassin::Timeout->new({ secs => $timeout });
 
   $options->{report}->enter_helper_run_mode();
@@ -633,8 +744,10 @@
 
     local $SIG{PIPE} = sub { die "__brokenpipe__ignore__\n" };
 
+    dbg("report: opening pipe: " . join(' ', $path, "-H", "-t", "many", "-x", "0", $opts, "< $tmpf"));
+
     my $pid = Mail::SpamAssassin::Util::helper_app_pipe_open(*DCC,
-        $tmpf, 1, $path, "-t", "many", split(' ', $opts));
+        $tmpf, 1, $path, "-H", "-t", "many", "-x", "0", split(' ', $opts));
     $pid or die "$!\n";
 
     my @ignored = <DCC>;
@@ -645,16 +758,16 @@
   $options->{report}->leave_helper_run_mode();
 
   if ($timer->timed_out()) {
-    dbg("reporter: DCC report timed out after $timeout seconds");
+    dbg("reporter: DCC report via dccproc timed out after $timeout seconds");
     return 0;
   }
 
   if ($err) {
     chomp $err;
     if ($err eq "__brokenpipe__ignore__") {
-      dbg("reporter: DCC report failed: broken pipe");
+      dbg("reporter: DCC report via dccproc failed: broken pipe");
     } else {
-      warn("reporter: DCC report failed: $err\n");
+      warn("reporter: DCC report via dccproc failed: $err\n");
     }
     return 0;
   }

Modified: spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/SPF.pm
URL: http://svn.apache.org/viewvc/spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/SPF.pm?rev=409236&r1=409235&r2=409236&view=diff
==============================================================================
--- spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/SPF.pm (original)
+++ spamassassin/branches/3.1/lib/Mail/SpamAssassin/Plugin/SPF.pm Wed May 24 13:04:44 2006
@@ -345,56 +345,8 @@
 sub _get_relay {
   my ($self, $scanner) = @_;
 
-  # return relay if already determined
-  return $scanner->{spf_relay} if exists $scanner->{spf_relay};
-
-  # DOS: For SPF checks we want to use the relay that passed the message to
-  # the internal network.  This relay can be any of the trusted relays or the
-  # first untrusted relay.  No matter which it is, the next (newer) relay has
-  # to be an internal relay.  If there are no trusted relays, the first
-  # untrusted relay is the one we want.  If internal_networks aren't set we
-  # have to assume all trusted relays are internal.
-
-  my $relay = undef;
-  my $relays_trusted = $scanner->{relays_trusted};
-
-  # no trusted relays, use first untrusted
-  if (scalar @{$relays_trusted} == 0) {
-    $relay = $scanner->{relays_untrusted}->[0];
-    dbg("spf: no trusted relays found, using first (untrusted) relay (if present) for SPF checks");
-  }
-
-  # last trusted relay is internal (or internal_networks not set), use first untrusted
-  elsif ($relays_trusted->[-1]->{internal} || !($scanner->{conf}->{internal_networks}->get_num_nets() > 0)) {
-    $relay = $scanner->{relays_untrusted}->[0];
-    dbg("spf: last trusted relay is internal, using first untrusted relay (parsed relay #". (scalar @{$relays_trusted}+1) ." if present) for SPF checks");
-  }
-
-  # find external relay that passed the message to the last internal relay
-  else {
-
-    # found an internal relay?
-    my $found = 0;
-
-    # start at the end; don't check for an internal relay before the first one
-    for (my $i = scalar @{$relays_trusted} - 1; $i > 0 && !$found; $i--) {
-      # if the next relay is internal, we can use the current external one
-      if ($relays_trusted->[$i-1]->{internal}) {
-	$relay = $relays_trusted->[$i];
-	$found = 1;
-	dbg("spf: using first external trusted relay (parsed relay #". ($i+1) .") for SPF checks");
-      }
-    }
-
-    # if none of the trusted relays were internal, internal_networks isn't set
-    # correctly -- dbg about it
-    if (!$found) {
-      dbg("spf: none of the trusted relays are internal, please check your internal_networks configuration");
-    }	
-  }
-
-  $scanner->{spf_relay} = $relay;
-  return $relay;
+  # dos: first external relay, not first untrusted
+  return $scanner->{relays_external}->[0];
 }
 
 sub _get_sender {

Modified: spamassassin/branches/3.1/t/config.dist
URL: http://svn.apache.org/viewvc/spamassassin/branches/3.1/t/config.dist?rev=409236&r1=409235&r2=409236&view=diff
==============================================================================
--- spamassassin/branches/3.1/t/config.dist (original)
+++ spamassassin/branches/3.1/t/config.dist Wed May 24 13:04:44 2006
@@ -7,6 +7,9 @@
 
 run_net_tests=n
 
+# Run DCC Tests
+run_dcc_tests=y
+
 # ---------------------------------------------------------------------------
 # Run SQL-based Auto-whitelist tests during 'make test' (additional
 # information required, below:)