> 1: Why call the first one in the rcpt chain at all? Just make it a
> connect plugin.
I could do this, and in fact i have attached an modified version of
'check_relay' which just does that. As it has otherwise the complete
same functionality as 'check_relay', you might think about replacing
the stock 'check_relay' with my version.
There seems to be one problem though (i think i remember we had this
already as a topic some time ago): It seems that a transaction->relaying
set in a connect plugin got lost by the time the rcpt plugins is
called. Currently the usual workaround in code (e.g. also done in the SMTP
AUTH Handler) is to set $ENV{RELAYCLIENT} instead.
I think i already suggested adding a connection->relaying flag, which
value is copied to transaction->relaying when a new transaction is startet.
This would allow us to get rid of using $ENV{RELAYCLIENT} as a flag, we
just should set it right before calling a queue plugin.
However i've added my 'check_relay' version for now.
-kju
--
It's an insane world, but i'm proud to be a part of it. -- Bill Hicks
#
# check_relay
#
# this is an modified version of the the stock version of 'check_relay'.
#
# At connect time it will check $ENV{RELAYCLIENT} and the 'relayclients'
# and 'morerelayclients' config files to see if relaying is allowed for
# this client. If this it the case, the plugin will set the relaying
# flag in transaction. It will return DECLINED in any case. The idea
# here is to have this knowledge available early, so blocking lists
# like dnsbl could ignore this client.
#
# At rcpt time it will check if relaying is allowed for this client by
# checking the relaying flag in transaction (which could also be set
# for example by the smtp auth code) and for legacy reasons also
# $ENV{RELAYCLIENT} again. If this is found not to be an relaying user,
# we next check 'rcpthosts' and 'morercpthosts' to see, if we accept
# mail for the recipient domain.
#
# This plugin should be the last in the rcpt-chain, the position in
# the connect-chain usually does not matter.
#
sub register {
my ($self, $qp) = @_;
$self->register_hook("connect", "check_relay_connect");
$self->register_hook("rcpt", "check_relay_rcpt");
}
sub check_relay_connect {
my ($self, $transaction, $recipient) = @_;
# Check if this IP is allowed to relay
my @relay_clients = $self->qp->config("relayclients");
my $more_relay_clients = $self->qp->config("morerelayclients", "map");
my %relay_clients = map { $_ => 1 } @relay_clients;
my $client_ip = $self->qp->connection->remote_ip;
while ($client_ip) {
if (exists($ENV{RELAYCLIENT}) or
exists($relay_clients{$client_ip}) or
exists($more_relay_clients->{$client_ip}))
{
$ENV{RELAYCLIENT} = '';
$transaction->relaying(1);
}
$client_ip =~ s/\d+\.?$//; # strip off another 8 bits
}
return(DECLINED);
}
sub check_relay_rcpt {
my ($self, $transaction, $recipient) = @_;
my $host = lc $recipient->host;
# Check if this is an relaying user
return(OK) if ( $transaction->{_relaying} || exists($ENV{RELAYCLIENT}) );
# Otherwise check for acceptance of the recipient host
my @rcpt_hosts = ($self->qp->config("me"), $self->qp->config("rcpthosts"));
# Allow 'no @' addresses for 'postmaster' and 'abuse'
# qmail-smtpd will do this for all users without a domain, but we'll
# be a bit more picky. Maybe that's a bad idea.
my $user = $recipient->user;
$host = $self->qp->config("me")
if ($host eq "" && (lc $user eq "postmaster" || lc $user eq "abuse"));
# Check if this recipient host is allowed
for my $allowed (@rcpt_hosts) {
$allowed =~ s/^\s*(\S+)/$1/;
return (OK) if $host eq lc $allowed;
return (OK) if substr($allowed,0,1) eq "." and $host =~ m/\Q$allowed\E$/i;
}
my $more_rcpt_hosts = $self->qp->config('morercpthosts', 'map');
return (OK) if exists $more_rcpt_hosts->{$host};
return (DENY);
}