#!/usr/bin/perl use Danga::DNS; sub register { my ($self) = @_; $self->register_hook('mail', 'mail_handler'); $self->register_hook('rcpt', 'rcpt_handler'); } sub mail_handler { my ($self, $transaction, $sender) = @_; my %rhsbl_zones_map = (); # Perform any RHS lookups in the background. We just send the query packets here # and pick up any results in the RCPT handler. # MTAs gets confused when you reject mail during MAIL FROM: my %rhsbl_zones = map { (split /\s+/, $_, 2)[0,1] } $self->config('rhsbl_zones'); if ($sender->format ne '<>' and %rhsbl_zones) { my $helo = $self->connection->hello_host; push(my @hosts, $sender->host); push(@hosts, $helo) if $helo && $helo ne $sender->host; for my $host (@hosts) { for my $rhsbl (keys %rhsbl_zones) { $self->log(LOGDEBUG, "Checking $host.$rhsbl for A record in the background"); Danga::DNS->new( callback => sub { $self->process_result($host, $rhsbl_zones{$rhsbl}, @_) }, host => "$host.$rhsbl", client => $self->qp->input_sock, ); } } } else { $self->log(LOGDEBUG, 'no RHS checks necessary'); } return DECLINED; } sub process_result { my ($self, $host, $template, $result, $query) = @_; if ($result !~ /^\d+\.\d+\.\d+\.\d+$/) { # NXDOMAIN or error return; } my $tran = $self->transaction; return if $tran->notes('rhsbl'); if ($host eq $tran->sender->host) { $tran->notes('rhsbl', "Mail from $host rejected because it $template"); } else { $tran->notes('rhsbl', "Mail from HELO $host rejected because it $template"); } } sub rcpt_handler { my ($self, $transaction, $rcpt) = @_; my $result = $transaction->notes('rhsbl'); return (DENY, $result) if $result; return DECLINED; }