The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

# <@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:
#
#
# 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>
use strict;
# use bytes;
use re 'taint';
our @ISA = qw(Mail::SpamAssassin::Plugin);
# constructor: register the eval rule
sub new {
my $class = shift;
my $mailsaobject = shift;
# some boilerplate...
$class = ref($class) || $class;
my $self = $class->SUPER::new($mailsaobject);
bless ($self, $class);
# the important bit!
$self->register_eval_rule("check_for_http_redirector"); # type does not matter
$self->register_eval_rule("check_https_ip_mismatch"); # type does not matter
$self->register_eval_rule("check_uri_truncated"); # type does not matter
return $self;
}
###########################################################################
sub check_for_http_redirector {
my ($self, $pms) = @_;
foreach ($pms->get_uri_list()) {
while (s{^https?://([^/:\?]+).+?(https?:/{0,2}?([^/:\?]+).*)$}{$2}i) {
my ($redir, $dest) = ($1, $3);
foreach ($redir, $dest) {
$_ = $self->{main}->{registryboundaries}->uri_to_domain($_) || $_;
}
next if ($redir eq $dest);
dbg("eval: redirect: found $redir to $dest, flagging");
return 1;
}
}
return 0;
}
###########################################################################
sub check_https_ip_mismatch {
my ($self, $pms) = @_;
foreach my $html (@{$pms->{html_all}}) {
foreach my $k (keys %{$html->{uri_detail}}) {
my $v = $html->{uri_detail}->{$k};
next if ($k !~ m%^https?:/*(?:[^\@/]+\@)?\d+\.\d+\.\d+\.\d+%i);
foreach (@{$v->{anchor_text}}) {
next if (m%^https:/*(?:[^\@/]+\@)?\d+\.\d+\.\d+\.\d+%i);
if (m%https:%i) {
return 1;
}
}
}
}
return 0;
}
###########################################################################
# is there a better way to do this?
sub check_uri_truncated {
my ($self, $pms) = @_;
return $pms->{'uri_truncated'} ? 1 : 0;
}
1;