Charlie Brady wrote:
http://markmail.org/message/sckrkzhtft34rqgg
Does anyone have existing literal badhelo matches which might match a
valid helo hostname if interpreted as an RE?
This might be a good opportunity to introduce standardization into
pattern matching plugins with common config file parser. I can offer up
my set, but once you see one, you don't need the rest. I use this
mechanism for _all_ pattern matching (mailfrom, from, rcptto, To, rdns,
body strings etc). They'll need a little tweaking because my plugins
themselves _never_ DENY, they use subsequent plugins to decide what
action to take (the notes() stuff).
Here's my helo plugin - note the NTMqplib::configpattern call, and the
if ( $host =~ /$self->{f_badhelo}/o ) { line.
use NTMqplib qw(configpattern);
sub register {
my ( $self, $qp, @args ) = @_;
&NTMqplib::configpattern( $self, 'badhelo' );
return;
}
# Doing this later (after MAILFROM) so the per-recipient
# domain configuration has been done by this point, and
# we know whether to do this or not.
sub hook_data {
my ( $self, $transaction ) = @_;
return DECLINED
if $transaction->notes('filter') !~ /yes/i
|| !$self->{f_badhelo}
|| $transaction->notes('reason');
my $host = $self->qp->connection->hello_host();
$host = lc $host;
return DECLINED if !$host;
if ( $host =~ /$self->{f_badhelo}/o ) {
my $content =
&NTMqplib::genreason( 'badhelo', $1, "Bad HELO/EHLO name
$host" );
$self->log( LOGINFO, $content );
$transaction->notes( 'reason', $content );
}
return DECLINED;
}
This is the configpattern function. It's job is to create a big
alternating pattern, where each line in the config file is one of the
alternates. If the config line is /.../ it's taken as a bare regexp.
If doesn't have /.../, it's taken literally, and \xXX encoded to de-meta
any characters there might be.
The pattern is unanchored. If you want to anchor (eg: insisting that
all rDNS entries have an implicit "$"), you do that in the plugin.
sub configpattern {
my ( $self, $parname ) = @_;
my @entries = $self->qp->config($parname);
return if !scalar(@entries);
my @cookedpatterns = ();
for my $p (@entries) {
next if $p =~ /^\s*#/;
next if $p =~ /^\s*$/;
if ( $p =~ /^\/(.*)\// ) {
push( @cookedpatterns, '(' . $1 . ')' );
} else {
$p =~ s/([^A-Za-z0-9])/sprintf("\\x%02x", ord($1))/ge;
push( @cookedpatterns, $p );
}
}
$cookedpattern = '(?i)(' . join( '|', @cookedpatterns ) . ')';
$self->{ 'f_' . $parname } = $cookedpattern;
$self->log( LOGDEBUG, "CONFIGPATTERN($parname): $cookedpattern" );
}