From 5c2c8455d5ad73573373930abb9e74a9fdcb2b22 Mon Sep 17 00:00:00 2001 From: John Peacock Date: Wed, 11 Jan 2006 17:03:45 +0000 Subject: [PATCH] Oops! Neglected to add this. Should have been part of r599. git-svn-id: https://svn.perl.org/qpsmtpd/branches/0.3x@601 958fd67b-6ff1-0310-b445-bb7760255be9 --- plugins/hosts_allow | 80 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 plugins/hosts_allow diff --git a/plugins/hosts_allow b/plugins/hosts_allow new file mode 100644 index 0000000..ca445c6 --- /dev/null +++ b/plugins/hosts_allow @@ -0,0 +1,80 @@ + +=head1 NAME + +hosts_allow - decide if a host is allowed to send mail + +=head1 DESCRIPTION + +The B module decides before the SMTP-Greeting if a host is +allowed to connect. It checks for too many (running) connections from one +host (see -m/--max-from-ip options in qpsmtpd-forkserver) and the config +file I. +The plugin takes no arguments. + +=head1 CONFIG + +The config file contains lines with two or three items. The first is either +an IP address or a network/mask pair. The second is a (valid) return code +from Qpsmtpd::Constants. The last is a comment which will be returned to the +connecting client if the return code is DENY or DENYSOFT (and of course +DENY_DISCONNECT and DENYSOFT_DISCONNECT). +Example: + + 192.168.3.4 DECLINED + 192.168.3.0/24 DENY Sorry, known spam only source + +This would exclude 192.168.3.4 from the DENY of 192.168.3.0/24. + +=cut + +use Qpsmtpd::Constants; +use Socket; + +sub hook_pre_connection { + my ($self,$transaction,%args) = @_; + + # remote_ip => inet_ntoa($iaddr), + # remote_port => $port, + # local_ip => inet_ntoa($laddr), + # local_port => $lport, + # max_conn_ip => $MAXCONNIP, + # child_addrs => [values %childstatus], + + my $remote = $args{remote_ip}; + + if ($args{max_conn_ip}) { + my $num_conn = 1; # seed with current value + my $raddr = inet_aton($remote); + foreach my $rip (@{$args{child_addrs}}) { + ++$num_conn if (defined $rip && $rip eq $raddr); + } + if ($num_conn > $args{max_conn_ip}) { + $self->log(LOGINFO, + "Too many connections from $remote: " + . "$num_conn > " . $args{max_conn_ip} + . "Denying connection."); + return (DENYSOFT, "Sorry, too many connections from $remote, " + ."try again later"); + } + } + + foreach ($self->qp->config("hosts_allow")) { + s/^\s*//; + my ($ipmask, $const, $message) = split /\s+/, $_, 3; + next unless defined $const; + + my ($net,$mask) = split '/', $ipmask, 2; + if (!defined $mask) { + $mask = 32; + } + $mask = pack "B32", "1"x($mask)."0"x(32-$mask); + if (join(".", unpack("C4", inet_aton($remote) & $mask)) eq $net) { + $const = Qpsmtpd::Constants::return_code($const) || DECLINED; + return($const, $message); + } + } + + return (DECLINED); +} + +# vim: sw=4 ts=4 expandtab syn=perl