Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

  • Note that this is my first SA plugin, so any feedback is welcome
  • This Plugin

ToDo

  • Words are hardcoded. Should be a configuration parameter instead.
  • Instead of checking for specific words, it might be better to "check if the image contains a certain amount of text", since it is not very likely that people send legitimate mail with text in imagescan only be a hint about spam, so don't set the score to high.

– Author: Maarten de Boer, mdeboer at iua dot upf dot edu

Changelog

Version 2:

  • Use convert instead of giftopnm, because I received some mails with .gif's that were actually .jpg's. convert handles that ok.
  • Some words added

Code

...

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

Code

relayed_by_dialup.cf

No Format
loadplugin Ocr OcrRelayedByDialup /etc/spamassassin/relayed_by_dialup.pm
body OCRheader RELAYED_BY_DIALUP        eval:checkrelayed_by_ocrdialup()
describe OCR Check if text in attached images contains spam words
score OCR 3.0

Ocr.pm

RELAYED_BY_DIALUP      Sent directly from dynamic IP address
score RELAYED_BY_DIALUP         1

relayed_by_dialup.pm

No Format

# 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
No Format

# Ocr plugin, version 2
package Ocr;

use strict;
use Mail::SpamAssassin;
use Mail::SpamAssassin::UtilPlugin;
use MailList::SpamAssassin::PluginUtil qw(sum);

our @ISA = qw (Mail::SpamAssassin::Plugin);

# constructor: register the eval rule$dbg_text = 'dynamic_relay: ';

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

sub checkrelayed_by_ocrdialup {
   my ( $self, $pms $permsgstatus) = @_;
   my $cnt$match = 0;
  # we need foreachthe myreveived $pheader ( $pms->{msg}->find_parts("image") ) {
      my ( $ctype, $boundary, $charset, $name ) =
        Mail::SpamAssassin::Util::parse_content_type(
         $p->get_header('content-type') 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 ( $ctype$relay->{no_reverse_dns} || $relay->{rdns} eq "image/gif"'' ) {
      Mail::SpamAssassin::Plugin::dbg($dbg_text . "cannot openperform, OCR,no "|/usr/bin/convert -flatten - pnm:-|/usr/bin/gocr -i - > /tmp/spamassassin.ocr.$$"rDNS");
      return 0;
    }

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

sub  open OCR, "/tmp/spamassassin.ocr.$$";
         my @words =
           ( 'company', 'money', 'stock', 'million', 'thousand', 'buy', 'price', 'don\'t' );
         while (<OCR>) {
            my $w;
            foreach $w (@words) {
               if (m/$w/i) {
                  $cnt++;
               }
            }
         }
         unlink "/tmp/spamassassin.ocr.$$";
      }
   }
   return ( $cnt > 1 );
}

1;_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;