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" );
}

Reply via email to