the pre-connection and post-connection hooks are not working in

qpsmtpd-forkserver. This patch merges Peter's patch (with the possibilty
to DENY/DENSOFT the connection) and my first attempt. The --max-from-ip
check was moved from core to the hosts_allow plugin. 

Patch by: Hanno Hecker <hah@uu-x.de>

git-svn-id: https://svn.perl.org/qpsmtpd/branches/0.3x@599 958fd67b-6ff1-0310-b445-bb7760255be9
This commit is contained in:
John Peacock 2006-01-11 16:21:08 +00:00
parent bfcd620a83
commit c0920346e5
3 changed files with 45 additions and 16 deletions

View File

@ -6,6 +6,12 @@
# plugins/http_config for details. # plugins/http_config for details.
# http_config http://localhost/~smtpd/config/ http://www.example.com/smtp.pl?config= # http_config http://localhost/~smtpd/config/ http://www.example.com/smtp.pl?config=
# The hosts_allow module must be loaded if you want the -m / --max-from-ip /
# my $MAXCONNIP = 5; # max simultaneous connections from one IP
# settings... without this it will NOT refuse more than $MAXCONNIP connections
# from one IP!
hosts_allow
quit_fortune quit_fortune
check_earlytalker check_earlytalker

View File

@ -84,6 +84,7 @@ sub disconnect {
my $self = shift; my $self = shift;
$self->log(LOGDEBUG,"click, disconnecting"); $self->log(LOGDEBUG,"click, disconnecting");
$self->SUPER::disconnect(@_); $self->SUPER::disconnect(@_);
$self->run_hooks("post-connection");
exit; exit;
} }

View File

@ -192,23 +192,34 @@ while (1) {
} }
IO::Handle::blocking($client, 1); IO::Handle::blocking($client, 1);
my ($port, $iaddr) = sockaddr_in($hisaddr); my ($port, $iaddr) = sockaddr_in($hisaddr);
if ($MAXCONNIP) { my $localsockaddr = getsockname($client);
my $num_conn = 1; # seed with current value my ($lport, $laddr) = sockaddr_in($localsockaddr);
foreach my $rip (values %childstatus) { my ($rc, @msg) = $qpsmtpd->run_hooks("pre-connection",
++$num_conn if (defined $rip && $rip eq $iaddr); remote_ip => inet_ntoa($iaddr),
} remote_port => $port,
local_ip => inet_ntoa($laddr),
if ($num_conn > $MAXCONNIP) { local_port => $lport,
my $rem_ip = inet_ntoa($iaddr); max_conn_ip => $MAXCONNIP,
::log(LOGINFO,"Too many connections from $rem_ip: " child_addrs => [values %childstatus],
."$num_conn > $MAXCONNIP. Denying connection."); );
$client->autoflush(1); if ($rc == DENYSOFT || $rc == DENYSOFT_DISCONNECT) {
print $client "451 Sorry, too many connections from $rem_ip, try again later\r\n"; unless ($msg[0]) {
close $client; @msg = ("Sorry, try again later");
next;
} }
&respond_client($client, 451, @msg);
close $client;
next;
} }
elsif ($rc == DENY || $rc == DENY_DISCONNECT) {
unless ($msg[0]) {
@msg = ("Sorry, service not available for you");
}
&respond_client($client, 550, @msg);
close $client;
next;
}
my $pid = safe_fork(); my $pid = safe_fork();
if ($pid) { if ($pid) {
# parent # parent
@ -231,8 +242,6 @@ while (1) {
::log(LOGINFO, "Connection Timed Out"); ::log(LOGINFO, "Connection Timed Out");
exit; }; exit; };
my $localsockaddr = getsockname($client);
my ($lport, $laddr) = sockaddr_in($localsockaddr);
$ENV{TCPLOCALIP} = inet_ntoa($laddr); $ENV{TCPLOCALIP} = inet_ntoa($laddr);
# my ($port, $iaddr) = sockaddr_in($hisaddr); # my ($port, $iaddr) = sockaddr_in($hisaddr);
$ENV{TCPREMOTEIP} = inet_ntoa($iaddr); $ENV{TCPREMOTEIP} = inet_ntoa($iaddr);
@ -256,6 +265,7 @@ while (1) {
); );
$qpsmtpd->run(); $qpsmtpd->run();
$qpsmtpd->run_hooks("post-connection");
exit; # child leaves exit; # child leaves
} }
} }
@ -265,6 +275,18 @@ sub log {
$qpsmtpd->log($level,$message); $qpsmtpd->log($level,$message);
} }
sub respond_client {
my ($client, $code, @message) = @_;
$client->autoflush(1);
while (my $msg = shift @message) {
my $line = $code . (@message?"-":" ").$msg;
::log(LOGDEBUG, $line);
print $client "$line\r\n"
or (::log(LOGERROR, "Could not print [$line]: $!"), return 0);
}
return 1;
}
### routine to protect process during fork ### routine to protect process during fork
sub safe_fork { sub safe_fork {