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 2022/05/15 09:05:13 UTC
svn commit: r1900917 - /spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/HashBL.pm
Author: hege
Date: Sun May 15 09:05:12 2022
New Revision: 1900917
URL: http://svn.apache.org/viewvc?rev=1900917&view=rev
Log:
Add check_hashbl_tag eval
Modified:
spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/HashBL.pm
Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/HashBL.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/HashBL.pm?rev=1900917&r1=1900916&r2=1900917&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/HashBL.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/HashBL.pm Sun May 15 09:05:12 2022
@@ -43,6 +43,11 @@ HashBL - query hashed (and unhashed) DNS
describe HASHBL_URI Message contains uri found on rbl
tflags HASHBL_URI net
+ # Capture tag using SA 4.0 regex named capture feature
+ header __X_SOME_ID X-Some-ID =~ /^(?<XSOMEID>\d{10,20})$/
+ # Query the tag value as is from a DNSBL
+ header HASHBL_TAG eval:check_hashbl_tag('idbl.example.invalid/A', 'raw', 'XSOMEID', '^127\.')
+
=head1 DESCRIPTION
This plugin support multiple types of hashed or unhashed DNS blocklists.
@@ -101,6 +106,8 @@ C<hashbl_email_regex>. Likewise, the de
C<hashbl_email_welcomelist>. Only change if you know what you are doing, see
module source for the defaults. Example: hashbl_email_regex \S+@\S+.com
+=back
+
=over 4
=item header RULE check_hashbl_uris('bl.example.invalid/A', 'OPTS', '^127\.')
@@ -114,6 +121,8 @@ Default OPTS: sha1/max=10/shuffle
=back
+=over 4
+
=item body RULE check_hashbl_bodyre('bl.example.invalid/A', 'OPTS', '\b(match)\b', '^127\.')
Search body for matching regexp and query the string captured. Regexp must
@@ -122,6 +131,19 @@ match DNS answer. Note that eval rule t
=back
+=over 4
+
+=item header RULE check_hashbl_tag('bl.example.invalid/A', 'OPTS', 'TAGNAME', '^127\.')
+
+Lookup value of SpamAssassin tag _TAGNAME_ from DNS list, optional subtest
+regexp to match DNS answer.
+
+DNS query type can be appended to list with /A (default) or /TXT.
+
+Default OPTS: sha1/max=10/shuffle
+
+=back
+
=cut
package Mail::SpamAssassin::Plugin::HashBL;
@@ -156,9 +178,15 @@ sub new {
$self->{hashbl_available} = 1;
}
- $self->register_eval_rule("check_hashbl_emails", $Mail::SpamAssassin::Conf::TYPE_HEAD_EVALS);
- $self->register_eval_rule("check_hashbl_uris", $Mail::SpamAssassin::Conf::TYPE_HEAD_EVALS);
- $self->register_eval_rule("check_hashbl_bodyre", $Mail::SpamAssassin::Conf::TYPE_BODY_EVALS);
+ $self->{evalfuncs} = {
+ 'check_hashbl_emails' => $Mail::SpamAssassin::Conf::TYPE_HEAD_EVALS,
+ 'check_hashbl_uris' => $Mail::SpamAssassin::Conf::TYPE_HEAD_EVALS,
+ 'check_hashbl_bodyre' => $Mail::SpamAssassin::Conf::TYPE_BODY_EVALS,
+ 'check_hashbl_tag' => $Mail::SpamAssassin::Conf::TYPE_HEAD_EVALS,
+ };
+ while (my ($func, $type) = each %{$self->{evalfuncs}}) {
+ $self->register_eval_rule($func, $type);
+ }
$self->set_config($mailsa->{conf});
return $self;
@@ -287,7 +315,7 @@ sub finish_parsing_start {
# Adjust priority -100 to launch early
# Find rulenames from eval_to_rule mappings
- foreach my $evalfunc ('check_hashbl_emails','check_hashbl_uris','check_hashbl_bodyre') {
+ foreach my $evalfunc (%{$self->{evalfuncs}}) {
foreach (@{$conf->{eval_to_rule}->{$evalfunc}||[]}) {
dbg("adjusting rule $_ priority to -100");
$conf->{priority}->{$_} = -100;
@@ -648,6 +676,91 @@ sub check_hashbl_bodyre {
return 0;
}
+sub check_hashbl_tag {
+ my ($self, $pms, $list, $opts, $tag, $subtest) = @_;
+
+ return 0 if !$self->{hashbl_available};
+ return 0 if !$pms->is_dns_available();
+
+ my $rulename = $pms->get_current_eval_rule_name();
+
+ if (!defined $list) {
+ warn "HashBL: $rulename blocklist argument missing\n";
+ return 0;
+ }
+
+ if (!defined $tag || $tag eq '') {
+ warn "HashBL: $rulename tag argument missing\n";
+ return 0;
+ }
+
+ if ($subtest) {
+ my ($rec, $err) = compile_regexp($subtest, 0);
+ if (!$rec) {
+ warn "HashBL: $rulename invalid subtest regex: $@\n";
+ return 0;
+ }
+ $subtest = $rec;
+ }
+
+ # Strip possible _ delimiters
+ $tag =~ s/^_(.+)_$/$1/;
+
+ # Force uppercase
+ $tag = uc($tag);
+
+ $pms->rule_pending($rulename); # mark async
+
+ $pms->action_depends_on_tags($tag, sub {
+ $self->_check_hashbl_tag($pms, $list, $opts, $tag, $subtest, $rulename);
+ });
+
+ return 0;
+}
+
+sub _check_hashbl_tag {
+ my ($self, $pms, $list, $opts, $tag, $subtest, $rulename) = @_;
+
+ # Defaults
+ $opts = 'sha1/max=10/shuffle' if !$opts;
+
+ # Filter list
+ my $keep_case = $opts =~ /\bcase\b/i;
+
+ # Get raw array of tag values, get_tag() returns joined string
+ my $valref = $pms->get_tag_raw($tag);
+
+ # Filter empty
+ my @vals = grep { defined $_ && $_ ne '' }
+ (ref $valref ? @$valref : $valref);
+
+ if (!@vals) {
+ $pms->rule_ready($rulename); # mark rule ready for metas
+ return;
+ }
+
+ # Lowercase
+ @vals = map { lc } @vals if !$keep_case;
+
+ # Unique
+ @vals = do { my %seen; grep { !$seen{$_}++ } @vals; };
+
+ # Randomize order
+ if ($opts =~ /\bshuffle\b/) {
+ Mail::SpamAssassin::Util::fisher_yates_shuffle(\@vals);
+ }
+
+ # Truncate list
+ my $max = $opts =~ /\bmax=(\d+)\b/ ? $1 : 10;
+ $#vals = $max-1 if scalar @vals > $max;
+
+ foreach my $value (@vals) {
+ $self->_submit_query($pms, $rulename, $value, $list, $opts, $subtest);
+ }
+
+ return;
+}
+
sub _hash {
my ($self, $opts, $value) = @_;
@@ -729,5 +842,6 @@ sub has_hashbl_ignore { 1 }
sub has_hashbl_email_regex { 1 }
sub has_hashbl_email_welcomelist { 1 }
sub has_hashbl_email_whitelist { 1 }
+sub has_hashbl_tag { 1 }
1;