=head1 NAME check_smtp_forward =head1 DESCRIPTION This plugin checks whether SMTP forwarding would be allowed for this recipient by connecting to the internal mail server. If the internal mail server rejects the mail, we DENY it. If the internal mail server would accept the mail, we DECLINE. If the internal mail server cannot be contacted, we DENYSOFT. =head1 CONFIG Reads smtproutes to determine where to send mail for various domains. Ignores any default smtproutes entries as they are for upstream mail servers (e.g. ISP). =head1 AUTHOR Copyright 2006 Gordon Rowell This software is free software and may be distributed under the same terms as qpsmtpd itself. Based in part on the smtp-forward plugin from the qpsmtpd distribution. =cut use Net::SMTP; sub register { my ($self, $qp, @args) = @_; for my $smtp_route ($self->qp->config("smtproutes")) { $smtp_route =~ s/[ \[ \] ]//g; my ($host, $server) = $smtp_route =~ m/(\S+):(\S+)/; next unless ($host); $self->{_smtp_host}{$host} = $server; $self->log(LOGDEBUG, "$host: $server"); } } sub hook_rcpt { my ($self, $transaction, $recipient) = @_; my $host = lc $recipient->host; my $server = $self->{_smtp_host}{$host} or return (DECLINED); my $port; ($server, $port) = split(/:/, $server); $port ||= 25; $self->log(LOGDEBUG, "Checking $recipient on $server:$port"); my $smtp = Net::SMTP->new( $server, Port => $port, Timeout => 60, Hello => $self->qp->config("me"), ) || return (DENYSOFT, "Unable to connect to $server: $!"); $smtp->mail( $transaction->sender->address || "" ); my $rc = $smtp->code; my $message = $smtp->message; chomp($message); if ($rc =~ m/^4\d{2}$/ ) { return(DENYSOFT, "Unable to queue message ($message)"); } elsif ($rc =~ m/^5\d{2}$/ ) { return(DENY, "Unable to queue message ($message)"); } $smtp->to($recipient->address); $rc = $smtp->code; $message = $smtp->message; chomp($message); if ($rc =~ m/^4\d{2}$/ ) { return(DENYSOFT, "Unable to queue message ($message)"); } elsif ($rc =~ m/^5\d{2}$/ ) { return(DENY, "Unable to queue message ($message)"); } $smtp->quit(); $rc = $smtp->code; $self->log(LOGDEBUG, "$server would accept message to $recipient"); return DECLINED; # Internal mail server is happy }