This Confluence has been LDAP enabled, if you are an ASF Committer, please use your LDAP Credentials to login. Any problems file an INFRA jira ticket please.

Page tree
Skip to end of metadata
Go to start of metadata

How it works

This plugin checks if a mail has been delivered directly from a dialup-IP. It simply uses the last trusted received-line for the IP and the DNS-Names and tries to find out if the IP-Number is somehow coded into the DNS.

Requirements

none.

Installation

Save the two files below in your local configuration directory.

Remarks

  • Note that this is my first SA plugin, so any feedback is welcome
  • This Plugin can only be a hint about spam, so don't set the score to high.

– Author: Lars Uffmann, lu at cachescrubber dot org, converted to a module by Cord Beermann, cord@Wunder-Nett.org

Code

relayed_by_dialup.cf

loadplugin RelayedByDialup /etc/spamassassin/relayed_by_dialup.pm
header RELAYED_BY_DIALUP        eval:relayed_by_dialup()
describe RELAYED_BY_DIALUP      Sent directly from dynamic IP address
score RELAYED_BY_DIALUP         1

relayed_by_dialup.pm

# written by Lars Uffmann <lu -at- cachescrubber -dot- org>
# converted to a SA-module by Cord Beermann <cord@Wunder-Nett.org>
# Licence: same as Spamassassin

package RelayedByDialup;
use Mail::SpamAssassin;
use Mail::SpamAssassin::Plugin;
use List::Util qw(sum);
our @ISA = qw(Mail::SpamAssassin::Plugin);

$dbg_text = 'dynamic_relay: ';

sub new {
  my ($class, $mailsa) = @_;
  $class = ref($class) || $class;
  my $self = $class->SUPER::new($mailsa);
  bless ($self, $class);
  $self->register_eval_rule ("relayed_by_dialup");
  return $self;
}

sub relayed_by_dialup {
  my ($self, $permsgstatus) = @_;
  my $match = 0;
  # we need the reveived header from _our_ first MX.
  # we can only match this if we have at least 1 untrusted header
  Mail::SpamAssassin::Plugin::dbg("dynamic_relay: starting");
  unless ($permsgstatus->{num_relays_untrusted} > 0) {
    Mail::SpamAssassin::Plugin::dbg("dynamic_relay: num_relays_untrusted undefined");
    return 0;
  } else {
    my $relay = $permsgstatus->{relays_untrusted}->[0];
    Mail::SpamAssassin::Plugin::dbg ("dynamic_relay: mx=" . $relay->{by});
    if ($relay->{no_reverse_dns} || $relay->{rdns} eq '' ) {
      Mail::SpamAssassin::Plugin::dbg($dbg_text . "cannot perform, no rDNS");
      return 0;
    }

    if (_is_dynamic_ip($relay->{ip}, $relay->{rdns})) {
      Mail::SpamAssassin::Plugin::dbg($dbg_text . "match: " . $relay->{ip} . "=" . $relay->{rdns});
      return 1;
    }
    Mail::SpamAssassin::Plugin::dbg($dbg_text . "tried: " . $relay->{ip} . "=" . $relay->{rdns});
    return 0;
  }
}

sub _is_dynamic_ip {
  my @ip = split(/\./, $_[0]);
  my $name = $_[1];
  return 0 unless $name;
  # convert addresses in hex to dotted decimal notation.
  $name =~ s/\b([a-f0-9]{8})\b/join(".", unpack("C*", pack("H8", $1)))/eg;
  # try shorter suffixes of $IP
  return 1 if _is_rr_dynamic_ip(join(".",@ip), $name);
  shift(@ip);
  return 1 if _is_rr_dynamic_ip(join(".",@ip), $name);
  return 0;
  # will lead to false positives ...
  shift(@ip);
  return 1 if _is_rr_dynamic_ip(join(".",@ip), $name);
  return 0;
}

sub _is_rr_dynamic_ip {
  my $ip = $_[0];
  my $is_ip = $_[1];
  # remove anything but digits > 0
  $is_ip =~ s/[^1-9]//g;
  # normalize the ip
  my $ip_test = $ip;
  # remove anything but digits > 0
  $ip_test =~ s/[0.]//g;
  my $diff = length($is_ip) - length($ip_test);
  return 0 if $diff < 0;
  my $offset = 0;
  my $ip_test_sum = sum(0, split("", $ip_test));
  do {
    my $test = substr($is_ip, $offset++, length($ip_test));
    my $is_ip_sum = sum(0, split("", $test));
    return 1 if $is_ip_sum == $ip_test_sum;
  } while ($diff--);
  return 0;
}

1;